markused: reduce hello world csize by 49%, do more cleanups and improvements (#24971)

This commit is contained in:
Felipe Pena 2025-07-29 03:00:57 -03:00 committed by GitHub
parent 59d408f72c
commit 396dc77a20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 424 additions and 303 deletions

View file

@ -1468,6 +1468,7 @@ fn (t Tree) index_expr(node ast.IndexExpr) &Node {
obj.add_terse('is_setter', t.bool_node(node.is_setter)) obj.add_terse('is_setter', t.bool_node(node.is_setter))
obj.add_terse('is_direct', t.bool_node(node.is_direct)) obj.add_terse('is_direct', t.bool_node(node.is_direct))
obj.add_terse('or_expr', t.or_expr(node.or_expr)) obj.add_terse('or_expr', t.or_expr(node.or_expr))
obj.add_terse('typ', t.type_node(node.typ))
obj.add('pos', t.pos(node.pos)) obj.add('pos', t.pos(node.pos))
return obj return obj
} }

View file

@ -134,7 +134,7 @@ pub fn tos2(s &u8) string {
// It will panic, when the pointer `s` is 0. // It will panic, when the pointer `s` is 0.
// It is the same as `tos2`, but for &char pointers, avoiding callsite casts. // It is the same as `tos2`, but for &char pointers, avoiding callsite casts.
// See also `tos_clone`. // See also `tos_clone`.
@[markused; unsafe] @[unsafe]
pub fn tos3(s &char) string { pub fn tos3(s &char) string {
if s == 0 { if s == 0 {
panic('tos3: nil string') panic('tos3: nil string')
@ -151,7 +151,7 @@ pub fn tos3(s &char) string {
// It returns '', when given a 0 pointer `s`, it does NOT panic. // It returns '', when given a 0 pointer `s`, it does NOT panic.
// It is the same as `tos5`, but for &u8 pointers, avoiding callsite casts. // It is the same as `tos5`, but for &u8 pointers, avoiding callsite casts.
// See also `tos_clone`. // See also `tos_clone`.
@[markused; unsafe] @[unsafe]
pub fn tos4(s &u8) string { pub fn tos4(s &u8) string {
if s == 0 { if s == 0 {
return '' return ''
@ -168,7 +168,7 @@ pub fn tos4(s &u8) string {
// It returns '', when given a 0 pointer `s`, it does NOT panic. // It returns '', when given a 0 pointer `s`, it does NOT panic.
// It is the same as `tos4`, but for &char pointers, avoiding callsite casts. // It is the same as `tos4`, but for &char pointers, avoiding callsite casts.
// See also `tos_clone`. // See also `tos_clone`.
@[markused; unsafe] @[unsafe]
pub fn tos5(s &char) string { pub fn tos5(s &char) string {
if s == 0 { if s == 0 {
return '' return ''

View file

@ -1207,6 +1207,7 @@ pub mut:
is_option bool // IfGuard is_option bool // IfGuard
is_direct bool // Set if the underlying memory can be safely accessed is_direct bool // Set if the underlying memory can be safely accessed
is_gated bool // #[] gated array is_gated bool // #[] gated array
typ Type
} }
@[minify] @[minify]

View file

@ -14,7 +14,6 @@ pub mut:
index bool // string[0] index bool // string[0]
range_index bool // string[0..1] range_index bool // string[0..1]
cast_ptr bool // &u8(...) cast_ptr bool // &u8(...)
asserts bool // assert expr
anon_fn bool // fn () { } anon_fn bool // fn () { }
auto_str bool // auto str fns auto_str bool // auto str fns
auto_str_ptr bool // auto str fns for ptr type auto_str_ptr bool // auto str fns for ptr type
@ -25,10 +24,8 @@ pub mut:
arr_pop bool // arr.pop() arr_pop bool // arr.pop()
arr_delete bool // arr.delete() arr_delete bool // arr.delete()
arr_reverse bool // arr.reverse() arr_reverse bool // arr.reverse()
arr_init bool // [1, 2, 3]
arr_map bool // []map[key]value arr_map bool // []map[key]value
type_name bool // var.type_name() type_name bool // var.type_name()
map_update bool // {...foo}
print_options bool // print option type print_options bool // print option type
print_types map[int]bool // print() idx types print_types map[int]bool // print() idx types
used_fns map[string]bool // filled in by markused used_fns map[string]bool // filled in by markused
@ -39,11 +36,8 @@ pub mut:
used_maps int // how many times maps were used, filled in by markused used_maps int // how many times maps were used, filled in by markused
used_none int // how many times `none` was used, filled in by markused used_none int // how many times `none` was used, filled in by markused
// json bool // json is imported // json bool // json is imported
debugger bool // debugger is used
comptime_calls map[string]bool // resolved name to call on comptime comptime_calls map[string]bool // resolved name to call on comptime
comptime_syms map[int]bool // resolved syms (generic) comptime_syms map[Type]bool // resolved syms (generic)
comptime_for bool // uses $for
memory_align bool // @[aligned] for struct
} }
@[unsafe] @[unsafe]

View file

@ -2385,9 +2385,7 @@ fn (mut c Checker) stmt(mut node ast.Stmt) {
} }
} }
ast.NodeError {} ast.NodeError {}
ast.DebuggerStmt { ast.DebuggerStmt {}
c.table.used_features.debugger = true
}
ast.AsmStmt { ast.AsmStmt {
c.asm_stmt(mut node) c.asm_stmt(mut node)
} }
@ -2398,9 +2396,6 @@ fn (mut c Checker) stmt(mut node ast.Stmt) {
} }
fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) { fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) {
if node.is_used {
c.table.used_features.asserts = true
}
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))
@ -5140,6 +5135,7 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
} }
c.stmts_ending_with_expression(mut node.or_expr.stmts, c.expected_or_type) c.stmts_ending_with_expression(mut node.or_expr.stmts, c.expected_or_type)
c.check_expr_option_or_result_call(node, typ) c.check_expr_option_or_result_call(node, typ)
node.typ = typ
return typ return typ
} }

View file

@ -277,7 +277,6 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
prev_inside_x_matches_type := c.inside_x_matches_type prev_inside_x_matches_type := c.inside_x_matches_type
c.push_new_comptime_info() c.push_new_comptime_info()
c.comptime.inside_comptime_for = true c.comptime.inside_comptime_for = true
c.table.used_features.comptime_for = true
if c.field_data_type == 0 { if c.field_data_type == 0 {
c.field_data_type = c.table.find_type('FieldData') c.field_data_type = c.table.find_type('FieldData')
} }
@ -322,7 +321,6 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.type_resolver.update_ct_type('${node.val_var}.typ', node.typ) c.type_resolver.update_ct_type('${node.val_var}.typ', node.typ)
c.stmts(mut node.stmts) c.stmts(mut node.stmts)
c.pop_comptime_info() c.pop_comptime_info()
c.table.used_features.comptime_for = true
} else { } else {
c.error('iterating over .values is supported only for enums, and ${sym.name} is not an enum', c.error('iterating over .values is supported only for enums, and ${sym.name} is not an enum',
node.typ_pos) node.typ_pos)
@ -340,7 +338,6 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.stmts(mut node.stmts) c.stmts(mut node.stmts)
c.pop_comptime_info() c.pop_comptime_info()
} }
c.table.used_features.comptime_for = true
} else if node.kind == .params { } else if node.kind == .params {
if !(sym.kind == .function || sym.name == 'FunctionData') { if !(sym.kind == .function || sym.name == 'FunctionData') {
c.error('iterating over `.params` is supported only for functions, and `${sym.name}` is not a function', c.error('iterating over `.params` is supported only for functions, and `${sym.name}` is not a function',

View file

@ -8,14 +8,14 @@ import v.token
fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
mut elem_type := ast.void_type mut elem_type := ast.void_type
unwrap_elem_type := c.unwrap_generic(node.elem_type) unwrap_elem_type := c.unwrap_generic(node.elem_type)
if node.typ.has_flag(.generic) {
c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
}
if c.pref.warn_about_allocs { if c.pref.warn_about_allocs {
c.warn_alloc('array initialization', node.pos) c.warn_alloc('array initialization', node.pos)
} }
// `x := []string{}` (the type was set in the parser) // `x := []string{}` (the type was set in the parser)
if node.typ != ast.void_type { 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 { if node.elem_type != 0 {
elem_sym := c.table.sym(node.elem_type) elem_sym := c.table.sym(node.elem_type)
c.check_any_type(node.elem_type, elem_sym, node.pos) c.check_any_type(node.elem_type, elem_sym, node.pos)
@ -159,9 +159,6 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
} }
// `[1,2,3]` // `[1,2,3]`
if node.exprs.len > 0 && node.elem_type == ast.void_type { 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 expected_value_type := ast.void_type
mut expecting_interface_array := false mut expecting_interface_array := false
mut expecting_sumtype_array := false mut expecting_sumtype_array := false
@ -502,6 +499,9 @@ fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
// `x := map[string]string` - set in parser // `x := map[string]string` - set in parser
if node.typ != 0 { if node.typ != 0 {
info := c.table.sym(node.typ).map_info() info := c.table.sym(node.typ).map_info()
if node.typ.has_flag(.generic) {
c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
}
if info.value_type != 0 { if info.value_type != 0 {
if info.value_type.has_flag(.result) { if info.value_type.has_flag(.result) {
c.error('cannot use Result type as map value type', node.pos) c.error('cannot use Result type as map value type', node.pos)
@ -541,7 +541,6 @@ 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 { 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 mut map_type := ast.void_type
use_expected_type := c.expected_type != ast.void_type && !c.inside_const use_expected_type := c.expected_type != ast.void_type && !c.inside_const
&& c.table.sym(c.expected_type).kind == .map && !(c.inside_fn_arg && c.table.sym(c.expected_type).kind == .map && !(c.inside_fn_arg

View file

@ -342,9 +342,15 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if c.pref.skip_unused { if c.pref.skip_unused {
if param.typ.has_flag(.generic) { if param.typ.has_flag(.generic) {
c.table.used_features.comptime_syms[c.unwrap_generic(param.typ)] = true c.table.used_features.comptime_syms[c.unwrap_generic(param.typ)] = true
c.table.used_features.comptime_syms[param.typ] = true
} }
if node.return_type.has_flag(.generic) { if node.return_type.has_flag(.generic) {
c.table.used_features.comptime_syms[c.unwrap_generic(node.return_type)] = true c.table.used_features.comptime_syms[c.unwrap_generic(node.return_type)] = true
c.table.used_features.comptime_syms[node.return_type] = true
}
if node.receiver.typ.has_flag(.generic) {
c.table.used_features.comptime_syms[node.receiver.typ] = true
c.table.used_features.comptime_syms[c.unwrap_generic(node.receiver.typ)] = true
} }
} }
if param.name == node.mod && param.name != 'main' { if param.name == node.mod && param.name != 'main' {
@ -1895,6 +1901,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
c.register_trace_call(node, func) c.register_trace_call(node, func)
if func.return_type.has_flag(.generic) { if func.return_type.has_flag(.generic) {
c.table.used_features.comptime_syms[typ.clear_option_and_result()] = true c.table.used_features.comptime_syms[typ.clear_option_and_result()] = true
c.table.used_features.comptime_syms[func.return_type] = true
} }
return typ return typ
} }
@ -2028,6 +2035,10 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
node.return_type = left_type node.return_type = left_type
node.receiver_type = left_type node.receiver_type = left_type
if is_generic {
c.table.used_features.comptime_syms[c.unwrap_generic(left_type)] = true
}
if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 { if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 {
c.table.unwrap_generic_type(left_type, c.table.cur_fn.generic_names, c.table.cur_concrete_types) c.table.unwrap_generic_type(left_type, c.table.cur_fn.generic_names, c.table.cur_concrete_types)
} }

View file

@ -68,10 +68,6 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
if node.language != .c && attr.name == 'typedef' { if node.language != .c && attr.name == 'typedef' {
c.error('`typedef` attribute can only be used with C structs', node.pos) c.error('`typedef` attribute can only be used with C structs', node.pos)
} }
aligned := if attr.arg == '' { 0 } else { attr.arg.int() }
if aligned > 1 {
c.table.used_features.memory_align = true
}
} }
// Evaluate the size of the unresolved fixed array // Evaluate the size of the unresolved fixed array
@ -533,6 +529,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
true) true)
if c.pref.skip_unused && node.typ.has_flag(.generic) { if c.pref.skip_unused && node.typ.has_flag(.generic) {
c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
c.table.used_features.comptime_syms[node.typ] = true
} }
} }
if !is_field_zero_struct_init { if !is_field_zero_struct_init {
@ -865,8 +862,6 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
mut info := first_sym.info as ast.Struct mut info := first_sym.info as ast.Struct
c.check_uninitialized_struct_fields_and_embeds(node, first_sym, mut info, mut c.check_uninitialized_struct_fields_and_embeds(node, first_sym, mut info, mut
inited_fields) inited_fields)
} else if first_sym.kind == .array {
c.table.used_features.arr_init = true
} }
} }
.none { .none {

View file

@ -175,7 +175,6 @@ fn (mut c Checker) markused_infixexpr(check bool) {
return return
} }
c.table.used_features.index = true 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) { fn (mut c Checker) markused_array_method(check bool, method_name string) {
@ -184,7 +183,6 @@ fn (mut c Checker) markused_array_method(check bool, method_name string) {
} }
match method_name { match method_name {
'' { // array init '' { // array init
c.table.used_features.arr_init = true
} }
'first' { 'first' {
c.table.used_features.arr_first = true c.table.used_features.arr_first = true

View file

@ -1702,6 +1702,9 @@ pub fn (mut g Gen) write_typedef_types() {
type_symbols := g.table.type_symbols.filter(!it.is_builtin type_symbols := g.table.type_symbols.filter(!it.is_builtin
&& it.kind in [.array, .array_fixed, .chan, .map]) && it.kind in [.array, .array_fixed, .chan, .map])
for sym in type_symbols { for sym in type_symbols {
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
continue
}
match sym.kind { match sym.kind {
.array { .array {
info := sym.info as ast.Array info := sym.info as ast.Array
@ -1752,9 +1755,6 @@ pub fn (mut g Gen) write_typedef_types() {
chan_inf := sym.chan_info() chan_inf := sym.chan_info()
chan_elem_type := chan_inf.elem_type chan_elem_type := chan_inf.elem_type
esym := g.table.sym(chan_elem_type) esym := g.table.sym(chan_elem_type)
if g.pref.skip_unused && esym.idx !in g.table.used_features.used_syms {
continue
}
g.type_definitions.writeln('typedef chan ${sym.cname};') g.type_definitions.writeln('typedef chan ${sym.cname};')
is_fixed_arr := esym.kind == .array_fixed is_fixed_arr := esym.kind == .array_fixed
if !chan_elem_type.has_flag(.generic) { if !chan_elem_type.has_flag(.generic) {
@ -1776,9 +1776,6 @@ static inline void __${sym.cname}_pushval(${sym.cname} ch, ${push_arg} val) {
} }
} }
.map { .map {
if g.pref.skip_unused && g.table.used_features.used_maps == 0 {
continue
}
g.type_definitions.writeln('typedef map ${sym.cname};') g.type_definitions.writeln('typedef map ${sym.cname};')
} }
else { else {
@ -2614,7 +2611,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.InterfaceDecl { ast.InterfaceDecl {
// definitions are sorted and added in write_types // definitions are sorted and added in write_types
ts := g.table.sym(node.typ) ts := g.table.sym(node.typ)
if !(ts.info as ast.Interface).is_generic { if !(ts.info as ast.Interface).is_generic
&& (!g.pref.skip_unused || ts.idx in g.table.used_features.used_syms) {
for method in node.methods { for method in node.methods {
if method.return_type.has_flag(.option) { if method.return_type.has_flag(.option) {
// Register an option if it's not registered yet // Register an option if it's not registered yet
@ -6711,7 +6709,8 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
} }
match sym.info { match sym.info {
ast.Struct { ast.Struct {
if !struct_names[name] { if !struct_names[name]
&& (!g.pref.skip_unused || sym.idx in g.table.used_features.used_syms) {
// generate field option types for fixed array of option struct before struct declaration // generate field option types for fixed array of option struct before struct declaration
opt_fields := sym.info.fields.filter(g.table.final_sym(it.typ).kind == .array_fixed) opt_fields := sym.info.fields.filter(g.table.final_sym(it.typ).kind == .array_fixed)
for opt_field in opt_fields { for opt_field in opt_fields {
@ -6733,15 +6732,13 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
} }
} }
} }
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
continue
}
g.struct_decl(sym.info, name, false, false) g.struct_decl(sym.info, name, false, false)
struct_names[name] = true struct_names[name] = true
} }
} }
ast.Thread { ast.Thread {
if !g.pref.is_bare && !g.pref.no_builtin { if !g.pref.is_bare && !g.pref.no_builtin
&& (!g.pref.skip_unused || sym.idx in g.table.used_features.used_syms) {
if g.pref.os == .windows { if g.pref.os == .windows {
if name == '__v_thread' { if name == '__v_thread' {
g.thread_definitions.writeln('typedef HANDLE ${name};') g.thread_definitions.writeln('typedef HANDLE ${name};')
@ -6814,7 +6811,8 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
ast.ArrayFixed { ast.ArrayFixed {
elem_sym := g.table.sym(sym.info.elem_type) elem_sym := g.table.sym(sym.info.elem_type)
if !elem_sym.is_builtin() && !sym.info.elem_type.has_flag(.generic) if !elem_sym.is_builtin() && !sym.info.elem_type.has_flag(.generic)
&& !sym.info.is_fn_ret { && (!g.pref.skip_unused || (!sym.info.is_fn_ret
&& sym.idx in g.table.used_features.used_syms)) {
// .array_fixed { // .array_fixed {
styp := sym.cname styp := sym.cname
// array_fixed_char_300 => char x[300] // array_fixed_char_300 => char x[300]
@ -6848,10 +6846,6 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
} }
g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];') g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];')
} else if !(elem_sym.info is ast.ArrayFixed && elem_sym.info.is_fn_ret) { } else if !(elem_sym.info is ast.ArrayFixed && elem_sym.info.is_fn_ret) {
if g.pref.skip_unused
&& elem_sym.idx !in g.table.used_features.used_syms {
continue
}
g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];') g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];')
} }
} }

View file

@ -1,3 +1,4 @@
pub struct C.atype {} pub struct C.atype {}
@[markused]
type BType = &C.atype type BType = &C.atype

View file

@ -10,6 +10,7 @@ fn (b Bar) b() {}
fn (b Bar) a() {} fn (b Bar) a() {}
@[markused]
struct Baz implements Foo { struct Baz implements Foo {
} }

View file

@ -8,7 +8,7 @@ import v.pref
// mark_used walks the AST, starting at main() and marks all used fns transitively. // mark_used walks the AST, starting at main() and marks all used fns transitively.
pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&ast.File) { pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&ast.File) {
mut all_fns, all_consts, all_globals, all_fields, all_decltypes, all_structs := all_global_decl(ast_files) mut all_fns, all_consts, all_globals, all_decltypes, all_structs := all_global_decl(ast_files)
util.timing_start('MARKUSED') util.timing_start('MARKUSED')
defer { defer {
util.timing_measure('MARKUSED') util.timing_measure('MARKUSED')
@ -17,11 +17,9 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
trace_skip_unused := pref_.compile_values['trace_skip_unused'] == 'true' trace_skip_unused := pref_.compile_values['trace_skip_unused'] == 'true'
trace_skip_unused_all_fns := pref_.compile_values['trace_skip_unused_all_fns'] == 'true' trace_skip_unused_all_fns := pref_.compile_values['trace_skip_unused_all_fns'] == 'true'
trace_skip_unused_fn_names := pref_.compile_values['trace_skip_unused_fn_names'] == 'true' trace_skip_unused_fn_names := pref_.compile_values['trace_skip_unused_fn_names'] == 'true'
trace_skip_unused_interface_methods := pref_.compile_values['trace_skip_unused_interface_methods'] == 'true'
trace_skip_unused_just_unused_fns := pref_.compile_values['trace_skip_unused_just_unused_fns'] == 'true' trace_skip_unused_just_unused_fns := pref_.compile_values['trace_skip_unused_just_unused_fns'] == 'true'
used_fns := pref_.compile_values['used_fns'] used_fns := pref_.compile_values['used_fns']
byteptr_idx_str := ast.byteptr_type_idx.str()
charptr_idx_str := ast.charptr_type_idx.str() charptr_idx_str := ast.charptr_type_idx.str()
string_idx_str := ast.string_type_idx.str() string_idx_str := ast.string_type_idx.str()
array_idx_str := ast.array_type_idx.str() array_idx_str := ast.array_type_idx.str()
@ -58,23 +56,13 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
} else { } else {
mut core_fns := [ mut core_fns := [
'main.main', 'main.main',
'init_global_allocator', // needed for linux_bare and wasm_bare
'memdup',
'tos',
'tos2',
'error',
'fast_string_eq',
'println',
'ptr_str',
] ]
if pref_.is_bare {
core_fns << 'init_global_allocator' // needed for linux_bare and wasm_bare
}
if ast_files[ast_files.len - 1].imports.len > 0 { if ast_files[ast_files.len - 1].imports.len > 0 {
core_fns << 'builtin_init' core_fns << 'builtin_init'
} }
if ast.float_literal_type.idx() in table.used_features.print_types
|| ast.f64_type_idx in table.used_features.print_types
|| ast.f32_type_idx in table.used_features.print_types {
include_panic_deps = true
}
if 'use_libbacktrace' in pref_.compile_defines { if 'use_libbacktrace' in pref_.compile_defines {
core_fns << 'print_libbacktrace' core_fns << 'print_libbacktrace'
} }
@ -96,13 +84,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
core_fns << '__new_array_with_array_default' core_fns << '__new_array_with_array_default'
core_fns << '__new_array_with_array_default_noscan' core_fns << '__new_array_with_array_default_noscan'
core_fns << 'new_array_from_c_array' core_fns << 'new_array_from_c_array'
// byteptr and charptr
core_fns << byteptr_idx_str + '.vstring'
core_fns << byteptr_idx_str + '.vstring_with_len'
core_fns << byteptr_idx_str + '.vstring_literal'
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 || pref_.is_shared { if table.used_features.index || pref_.is_shared {
include_panic_deps = true include_panic_deps = true
@ -132,10 +113,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
core_fns << string_idx_str + '.repeat' core_fns << string_idx_str + '.repeat'
core_fns << 'tos3' core_fns << 'tos3'
} }
if table.used_features.auto_str_ptr {
include_panic_deps = true
core_fns << 'isnil'
}
if table.used_features.arr_prepend { if table.used_features.arr_prepend {
core_fns << ref_array_idx_str + '.prepend_many' core_fns << ref_array_idx_str + '.prepend_many'
} }
@ -163,35 +140,10 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
builderptr_idx + '.write_rune', builderptr_idx + '.write_rune',
] ]
} }
if !table.used_features.arr_init {
table.used_features.arr_init = table.used_features.print_types.keys().any(table.type_to_str(it).contains('[]'))
}
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_default'
core_fns << '__new_array_with_default_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 << ref_array_idx_str + '.set'
}
if table.used_features.comptime_for {
include_panic_deps = true
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'
core_fns << ref_array_idx_str + '.set'
}
if table.used_features.print_options { if table.used_features.print_options {
include_panic_deps = true include_panic_deps = true
core_fns << '_option_ok' core_fns << '_option_ok'
core_fns << '_result_ok' core_fns << '_result_ok'
core_fns << charptr_idx_str + '.vstring_literal'
} }
if table.used_features.anon_fn { if table.used_features.anon_fn {
core_fns << 'memdup_uncollectable' core_fns << 'memdup_uncollectable'
@ -207,21 +159,9 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
core_fns << ref_densearray_idx_str + '.clone' core_fns << ref_densearray_idx_str + '.clone'
core_fns << map_idx_str + '.clone' core_fns << map_idx_str + '.clone'
} }
if table.used_features.map_update {
include_panic_deps = true
core_fns << 'new_map_update_init'
}
if table.used_features.asserts {
include_panic_deps = true
core_fns << '__print_assert_failure'
core_fns << 'isnil'
}
if table.used_features.type_name { if table.used_features.type_name {
core_fns << charptr_idx_str + '.vstring_literal' core_fns << charptr_idx_str + '.vstring_literal'
} }
if table.used_features.memory_align {
core_fns << 'memdup_align'
}
if pref_.trace_calls || pref_.trace_fns.len > 0 { if pref_.trace_calls || pref_.trace_fns.len > 0 {
include_panic_deps = true include_panic_deps = true
core_fns << 'vgettid' core_fns << 'vgettid'
@ -234,6 +174,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
core_fns << '_result_ok' core_fns << '_result_ok'
core_fns << 'tos5' core_fns << 'tos5'
core_fns << 'time.unix' // used by json core_fns << 'time.unix' // used by json
core_fns << 'error'
include_panic_deps = true include_panic_deps = true
} }
if pref_.should_use_segfault_handler() { if pref_.should_use_segfault_handler() {
@ -277,38 +218,12 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
} }
if mfn.is_method { if mfn.is_method {
method_receiver_typename := table.type_to_str(mfn.receiver.typ) method_receiver_typename := table.type_to_str(mfn.receiver.typ)
if method_receiver_typename == '&wyrand.WyRandRNG' {
// WyRandRNG is the default rand pseudo random generator
all_fn_root_names << k
continue
}
if table.used_features.auto_str && method_receiver_typename == '&strings.Builder' {
// implicit string builders are generated in auto_eq_methods.v
all_fn_root_names << k
continue
}
if method_receiver_typename == '&sync.Channel' { if method_receiver_typename == '&sync.Channel' {
all_fn_root_names << k all_fn_root_names << k
continue continue
} }
if mfn.name in ['+', '-', '*', '%', '/', '<', '=='] {
// TODO: mark the used operators in the checker
all_fn_root_names << k
continue
}
} }
has_dot := k.contains('.') has_dot := k.contains('.')
// auto generated string interpolation functions, may
// call .str or .auto_str methods for user types:
if table.used_features.auto_str || table.used_features.dump || table.used_features.asserts
|| table.used_features.debugger
|| table.used_features.print_types[mfn.receiver.typ.idx()] {
if (has_dot && (k.ends_with('.str') || k.ends_with('.auto_str')))
|| (k.starts_with('_Atomic_') && k.ends_with('_str')) {
all_fn_root_names << k
continue
}
}
if has_dot { if has_dot {
if k.ends_with('.init') || k.ends_with('.cleanup') { if k.ends_with('.init') || k.ends_with('.cleanup') {
all_fn_root_names << k all_fn_root_names << k
@ -319,10 +234,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
all_fn_root_names << k all_fn_root_names << k
continue continue
} }
if (pref_.autofree || include_panic_deps) && k.ends_with('.free') {
all_fn_root_names << k
continue
}
if k.ends_with('.lock') || k.ends_with('.unlock') || k.ends_with('.rlock') if k.ends_with('.lock') || k.ends_with('.unlock') || k.ends_with('.rlock')
|| k.ends_with('.runlock') { || k.ends_with('.runlock') {
all_fn_root_names << k all_fn_root_names << k
@ -347,12 +258,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
continue continue
} }
} }
if mfn.receiver.typ != ast.void_type && mfn.generic_names.len > 0 {
// generic methods may be used in cgen after specialisation :-|
// TODO: move generic method specialisation from cgen to before markused
all_fn_root_names << k
continue
}
if pref_.prealloc && k.starts_with('prealloc_') { if pref_.prealloc && k.starts_with('prealloc_') {
all_fn_root_names << k all_fn_root_names << k
continue continue
@ -376,44 +281,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
} }
} }
// handle interface implementation methods:
for isym in table.type_symbols {
if isym.kind != .interface {
continue
}
if isym.info !is ast.Interface {
// Do not remove this check, isym.info could be &IError.
continue
}
interface_info := isym.info as ast.Interface
if interface_info.methods.len == 0 {
continue
}
for itype in interface_info.types {
ptype := itype.set_nr_muls(1)
ntype := itype.set_nr_muls(0)
interface_types := [ptype, ntype]
for method in interface_info.methods {
for typ in interface_types {
interface_implementation_method_name := int(typ.clear_flags()).str() + '.' +
method.name
if trace_skip_unused_interface_methods {
eprintln('>> isym.name: ${isym.name} | interface_implementation_method_name: ${interface_implementation_method_name}')
}
all_fn_root_names << interface_implementation_method_name
}
}
for embed_method in table.get_embed_methods(table.sym(itype)) {
interface_implementation_method_name :=
int(embed_method.params[0].typ.clear_flags()).str() + '.' + embed_method.name
if trace_skip_unused_interface_methods {
eprintln('>> isym.name: ${isym.name} | interface_implementation_method_name: ${interface_implementation_method_name} (embeded)')
}
all_fn_root_names << interface_implementation_method_name
}
}
}
handle_vweb(mut table, mut all_fn_root_names, 'veb.Result', 'veb.filter', 'veb.Context') handle_vweb(mut table, mut all_fn_root_names, 'veb.Result', 'veb.filter', 'veb.Context')
handle_vweb(mut table, mut all_fn_root_names, 'vweb.Result', 'vweb.filter', 'vweb.Context') 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_vweb(mut table, mut all_fn_root_names, 'x.vweb.Result', 'x.vweb.filter', 'x.vweb.Context')
@ -448,24 +315,20 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
all_fns: all_fns all_fns: all_fns
all_consts: all_consts all_consts: all_consts
all_globals: all_globals all_globals: all_globals
all_fields: all_fields
all_decltypes: all_decltypes all_decltypes: all_decltypes
all_structs: all_structs all_structs: all_structs
pref: pref_ pref: pref_
trace_enabled: 'trace_skip_unused_walker' in pref_.compile_defines
) )
walker.mark_markused_consts() // tagged with `@[markused]` walker.mark_markused_consts() // tagged with `@[markused]`
walker.mark_markused_globals() // tagged with `@[markused]` walker.mark_markused_globals() // tagged with `@[markused]`
walker.mark_markused_syms() // tagged with `@[markused]` walker.mark_markused_syms() // tagged with `@[markused]`
walker.mark_markused_fns() // tagged with `@[markused]`, `@[export]` and veb actions walker.mark_markused_fns() // tagged with `@[markused]`, `@[export]` and veb actions
walker.mark_markused_decltypes() // tagged with `@[markused]` walker.mark_markused_decltypes() // tagged with `@[markused]`
walker.mark_struct_field_default_expr() walker.mark_generic_types()
for k, _ in table.used_features.comptime_calls { if pref_.use_cache {
walker.fn_by_name(k) walker.mark_by_sym_name('IError')
}
for k, _ in table.used_features.comptime_syms {
walker.mark_by_sym(table.sym(k))
} }
walker.mark_root_fns(all_fn_root_names) walker.mark_root_fns(all_fn_root_names)
@ -473,6 +336,30 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
walker.mark_by_sym_name('vweb.RedirectParams') walker.mark_by_sym_name('vweb.RedirectParams')
walker.mark_by_sym_name('vweb.RequestParams') walker.mark_by_sym_name('vweb.RequestParams')
for kcon, con in all_consts {
if pref_.is_shared && con.is_pub {
walker.mark_const_as_used(kcon)
continue
}
if pref_.translated && con.attrs.any(it.name == 'export') {
walker.mark_const_as_used(kcon)
continue
}
}
if trace_skip_unused_fn_names {
for key, _ in walker.used_fns {
println('> used fn key: ${key}')
}
}
walker.finalize(include_panic_deps)
table.used_features.used_none = walker.used_none
if walker.used_none == 0 {
walker.used_fns.delete('${int(ast.none_type)}.str')
}
if table.used_features.used_maps > 0 { if table.used_features.used_maps > 0 {
for k, mut mfn in all_fns { for k, mut mfn in all_fns {
mut method_receiver_typename := '' mut method_receiver_typename := ''
@ -508,30 +395,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
} }
} }
for kcon, con in all_consts {
if pref_.is_shared && con.is_pub {
walker.mark_const_as_used(kcon)
continue
}
if pref_.translated && con.attrs.any(it.name == 'export') {
walker.mark_const_as_used(kcon)
continue
}
}
if trace_skip_unused_fn_names {
for key, _ in walker.used_fns {
println('> used fn key: ${key}')
}
}
table.used_features.used_none = walker.used_none
if walker.used_none == 0 {
walker.used_fns.delete('${int(ast.none_type)}.str')
}
walker.finalize(include_panic_deps)
table.used_features.used_fns = walker.used_fns.move() table.used_features.used_fns = walker.used_fns.move()
table.used_features.used_consts = walker.used_consts.move() table.used_features.used_consts = walker.used_consts.move()
table.used_features.used_globals = walker.used_globals.move() table.used_features.used_globals = walker.used_globals.move()
@ -556,7 +419,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
} }
} }
fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.StructField, map[string]ast.Type, map[string]ast.StructDecl) { fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.TypeDecl, map[string]ast.StructDecl) {
util.timing_start(@METHOD) util.timing_start(@METHOD)
defer { defer {
util.timing_measure(@METHOD) util.timing_measure(@METHOD)
@ -564,8 +427,7 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast
mut all_fns := map[string]ast.FnDecl{} mut all_fns := map[string]ast.FnDecl{}
mut all_consts := map[string]ast.ConstField{} mut all_consts := map[string]ast.ConstField{}
mut all_globals := map[string]ast.GlobalField{} mut all_globals := map[string]ast.GlobalField{}
mut all_fields := map[string]ast.StructField{} mut all_decltypes := map[string]ast.TypeDecl{}
mut all_decltypes := map[string]ast.Type{}
mut all_structs := map[string]ast.StructDecl{} mut all_structs := map[string]ast.StructDecl{}
for i in 0 .. ast_files.len { for i in 0 .. ast_files.len {
for node in ast_files[i].stmts { for node in ast_files[i].stmts {
@ -589,20 +451,18 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast
} }
} }
ast.StructDecl { ast.StructDecl {
for sfield in node.fields {
sfkey := sfield.sfkey()
all_fields[sfkey] = sfield
}
all_structs[node.name] = node all_structs[node.name] = node
} }
ast.TypeDecl { ast.TypeDecl {
all_decltypes[node.name] = node.typ if node.is_markused {
all_decltypes[node.name] = node
}
} }
else {} else {}
} }
} }
} }
return all_fns, all_consts, all_globals, all_fields, all_decltypes, all_structs return all_fns, all_consts, all_globals, all_decltypes, all_structs
} }
fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) { fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) {

View file

@ -9,32 +9,33 @@ import v.pref
pub struct Walker { pub struct Walker {
pub mut: pub mut:
table &ast.Table = unsafe { nil } table &ast.Table = unsafe { nil }
features &ast.UsedFeatures = unsafe { nil } features &ast.UsedFeatures = unsafe { nil }
used_fns map[string]bool // used_fns['println'] == true used_fns map[string]bool // used_fns['println'] == true
used_consts map[string]bool // used_consts['os.args'] == true trace_enabled bool
used_globals map[string]bool used_consts map[string]bool // used_consts['os.args'] == true
used_fields map[string]bool used_globals map[string]bool
used_syms map[int]bool used_fields map[string]bool
used_none int // _option_none used_syms map[int]bool
used_option int // _option_ok used_none int // _option_none
used_result int // _result_ok used_option int // _option_ok
used_panic int // option/result propagation used_result int // _result_ok
used_interp int // str interpolation used_panic int // option/result propagation
n_asserts int pref &pref.Preferences = unsafe { nil }
pref &pref.Preferences = unsafe { nil }
mut: mut:
files []&ast.File files []&ast.File
all_fns map[string]ast.FnDecl all_fns map[string]ast.FnDecl
all_consts map[string]ast.ConstField all_consts map[string]ast.ConstField
all_globals map[string]ast.GlobalField all_globals map[string]ast.GlobalField
all_fields map[string]ast.StructField all_fields map[string]ast.StructField
all_decltypes map[string]ast.Type all_decltypes map[string]ast.TypeDecl
all_structs map[string]ast.StructDecl all_structs map[string]ast.StructDecl
level int
is_builtin_mod bool is_builtin_mod bool
// dependencies finding flags // dependencies finding flags
uses_atomic bool // has atomic
uses_array bool // has array uses_array bool // has array
uses_channel bool // has chan dep uses_channel bool // has chan dep
uses_lock bool // has mutex dep uses_lock bool // has mutex dep
@ -46,6 +47,20 @@ mut:
uses_ct_attribute bool // $for .attributes uses_ct_attribute bool // $for .attributes
uses_external_type bool uses_external_type bool
uses_err bool // err var uses_err bool // err var
uses_asserts bool // assert
uses_map_update bool // has {...expr}
uses_debugger bool // has debugger;
uses_mem_align bool // @[aligned:N] for structs
uses_eq bool // has == op
uses_interp bool // string interpolation
uses_guard bool
uses_orm bool
uses_str bool // has .str() call
uses_free bool // has .free() call
uses_spawn bool
uses_dump bool
uses_memdup bool // sumtype cast and &Struct{}
uses_arr_void bool // auto arr methods
} }
pub fn Walker.new(params Walker) &Walker { pub fn Walker.new(params Walker) &Walker {
@ -92,6 +107,9 @@ pub fn (mut w Walker) mark_const_as_used(ckey string) {
return return
} }
w.used_consts[ckey] = true w.used_consts[ckey] = true
if ckey == 'c' {
println(ckey)
}
cfield := w.all_consts[ckey] or { return } cfield := w.all_consts[ckey] or { return }
w.expr(cfield.expr) w.expr(cfield.expr)
w.mark_by_type(cfield.typ) w.mark_by_type(cfield.typ)
@ -118,7 +136,6 @@ pub fn (mut w Walker) mark_struct_field_default_expr_as_used(sfkey string) {
} }
w.used_fields[sfkey] = true w.used_fields[sfkey] = true
sfield := w.all_fields[sfkey] or { return } sfield := w.all_fields[sfkey] or { return }
w.expr(sfield.default_expr) w.expr(sfield.default_expr)
} }
@ -149,6 +166,9 @@ pub fn (mut w Walker) mark_markused_fns() {
} }
pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) { pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) {
if w.trace_enabled {
eprintln('>>>>>>> ROOT ${all_fn_root_names}')
}
for fn_name in all_fn_root_names { for fn_name in all_fn_root_names {
if fn_name !in w.used_fns { if fn_name !in w.used_fns {
$if trace_skip_unused_roots ? { $if trace_skip_unused_roots ? {
@ -192,15 +212,9 @@ pub fn (mut w Walker) mark_markused_syms() {
} }
pub fn (mut w Walker) mark_markused_decltypes() { pub fn (mut w Walker) mark_markused_decltypes() {
for _, typ in w.all_decltypes { for _, decl in w.all_decltypes {
w.mark_by_type(typ) if decl.is_markused {
} w.mark_by_type(decl.typ)
}
pub fn (mut w Walker) mark_struct_field_default_expr() {
for sfkey, mut structfield in w.all_fields {
if structfield.has_default_expr {
w.mark_struct_field_default_expr_as_used(sfkey)
} }
} }
} }
@ -209,14 +223,16 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) {
mut node := unsafe { node_ } mut node := unsafe { node_ }
match mut node { match mut node {
ast.EmptyStmt {} ast.EmptyStmt {}
ast.DebuggerStmt {} ast.DebuggerStmt {
w.uses_debugger = true
}
ast.AsmStmt { ast.AsmStmt {
w.asm_io(node.output) w.asm_io(node.output)
w.asm_io(node.input) w.asm_io(node.input)
} }
ast.AssertStmt { ast.AssertStmt {
if node.is_used { if node.is_used {
w.n_asserts++ w.uses_asserts = true
w.expr(node.expr) w.expr(node.expr)
if node.extra !is ast.EmptyExpr { if node.extra !is ast.EmptyExpr {
w.expr(node.extra) w.expr(node.extra)
@ -314,12 +330,16 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) {
w.expr(line.where_expr) w.expr(line.where_expr)
w.exprs(line.update_exprs) w.exprs(line.update_exprs)
} }
w.uses_orm = true
} }
ast.StructDecl { ast.StructDecl {
for typ in node.implements_types { for typ in node.implements_types {
w.mark_by_type(typ.typ) w.mark_by_type(typ.typ)
} }
w.struct_fields(node.fields) w.struct_fields(node.fields)
if !w.uses_mem_align {
w.uses_mem_align = node.attrs.contains('aligned')
}
} }
ast.DeferStmt { ast.DeferStmt {
w.stmts(node.stmts) w.stmts(node.stmts)
@ -381,7 +401,12 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.fn_decl(mut node.decl) w.fn_decl(mut node.decl)
} }
ast.ArrayInit { ast.ArrayInit {
w.mark_by_type(node.elem_type) sym := w.table.sym(node.elem_type)
w.mark_by_sym(sym)
if sym.info is ast.Thread {
w.mark_by_type(w.table.find_or_register_array(sym.info.return_type))
}
w.mark_by_type(node.typ)
w.expr(node.len_expr) w.expr(node.len_expr)
w.expr(node.cap_expr) w.expr(node.cap_expr)
w.expr(node.init_expr) w.expr(node.init_expr)
@ -398,18 +423,35 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.call_expr(mut node) w.call_expr(mut node)
if node.name == 'json.decode' { if node.name == 'json.decode' {
w.mark_by_type((node.args[0].expr as ast.TypeNode).typ) w.mark_by_type((node.args[0].expr as ast.TypeNode).typ)
} else if node.name == 'json.encode' && node.args[0].typ != 0 {
sym := w.table.final_sym(node.args[0].typ)
if sym.info is ast.Map {
w.mark_by_type(w.table.find_or_register_array(sym.info.key_type))
}
} else if !w.uses_str && node.is_method && node.name == 'str' {
w.uses_str = true
} else if !w.uses_free && node.is_method && node.name == 'free' {
w.uses_free = true
} }
if !w.is_builtin_mod && !w.uses_external_type { if !w.is_builtin_mod && !w.uses_external_type {
if node.is_method { if node.is_method {
w.uses_external_type = node.mod == 'builtin' w.uses_external_type = node.mod == 'builtin'
} else if node.name.contains('.') { } else if node.name.contains('.') && node.name.all_before_last('.').len > 1 {
w.uses_external_type = true w.uses_external_type = true
} }
} }
if node.is_method && node.left_type != 0
&& w.table.final_sym(node.left_type).kind in [.array_fixed, .array] {
w.mark_by_type(node.return_type)
}
} }
ast.CastExpr { ast.CastExpr {
w.expr(node.expr) w.expr(node.expr)
w.expr(node.arg) w.expr(node.arg)
if !w.uses_memdup {
fsym := w.table.final_sym(node.typ)
w.uses_memdup = fsym.kind == .sum_type
}
w.mark_by_type(node.typ) w.mark_by_type(node.typ)
if node.typ.has_flag(.option) { if node.typ.has_flag(.option) {
w.used_option++ w.used_option++
@ -441,8 +483,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
} }
ast.DumpExpr { ast.DumpExpr {
w.expr(node.expr) w.expr(node.expr)
w.fn_by_name('eprint') w.uses_dump = true
w.fn_by_name('eprintln')
w.mark_by_type(node.expr_type) w.mark_by_type(node.expr_type)
} }
ast.SpawnExpr { ast.SpawnExpr {
@ -450,7 +491,8 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.fn_by_name('free') w.fn_by_name('free')
} }
w.expr(node.call_expr) w.expr(node.call_expr)
w.fn_by_name('tos3') w.uses_spawn = true
if w.pref.os == .windows { if w.pref.os == .windows {
w.fn_by_name('panic_lasterr') w.fn_by_name('panic_lasterr')
w.fn_by_name('winapi_lasterr_str') w.fn_by_name('winapi_lasterr_str')
@ -463,11 +505,16 @@ fn (mut w Walker) expr(node_ ast.Expr) {
if node.is_expr { if node.is_expr {
w.fn_by_name('free') w.fn_by_name('free')
} }
w.mark_by_type(node.call_expr.return_type)
w.expr(node.call_expr) w.expr(node.call_expr)
} }
ast.IndexExpr { ast.IndexExpr {
w.expr(node.left) w.expr(node.left)
w.expr(node.index) w.expr(node.index)
if node.or_expr.kind == .block {
w.uses_guard = true
}
w.mark_by_type(node.typ)
w.or_block(node.or_expr) w.or_block(node.or_expr)
if node.left_type == 0 { if node.left_type == 0 {
return return
@ -505,8 +552,8 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.expr(node.right) w.expr(node.right)
w.or_block(node.or_block) w.or_block(node.or_block)
if node.left_type != 0 { if node.left_type != 0 {
w.mark_by_type(node.left_type)
sym := w.table.sym(node.left_type) sym := w.table.sym(node.left_type)
w.mark_by_sym(sym)
if sym.kind == .struct { if sym.kind == .struct {
if opmethod := sym.find_method(node.op.str()) { if opmethod := sym.find_method(node.op.str()) {
unsafe { unsafe {
@ -527,14 +574,21 @@ fn (mut w Walker) expr(node_ ast.Expr) {
if right_sym.kind == .map { if right_sym.kind == .map {
w.features.used_maps++ w.features.used_maps++
} }
if !w.uses_arr_void && right_sym.kind in [.array, .array_fixed] {
w.uses_arr_void = true
}
} else if node.op in [.key_is, .not_is] { } else if node.op in [.key_is, .not_is] {
w.mark_by_sym(right_sym) w.mark_by_sym(right_sym)
} }
} }
if !w.uses_eq && node.op in [.eq, .ne] {
w.uses_eq = true
}
} }
ast.IfGuardExpr { ast.IfGuardExpr {
w.expr(node.expr) w.expr(node.expr)
w.mark_by_type(node.expr_type) w.mark_by_type(node.expr_type)
w.uses_guard = true
} }
ast.IfExpr { ast.IfExpr {
w.expr(node.left) w.expr(node.left)
@ -557,8 +611,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
.global { .global {
w.mark_global_as_used(node.name) w.mark_global_as_used(node.name)
} }
.blank_ident {}
else { else {
// `.unresolved`, `.blank_ident`, `.variable`, `.function` // `.unresolved`, `.variable`
// println('>>> else, ast.Ident ${node.name} kind: $node.kind ') // println('>>> else, ast.Ident ${node.name} kind: $node.kind ')
if node.name in w.all_consts { if node.name in w.all_consts {
w.mark_const_as_used(node.name) w.mark_const_as_used(node.name)
@ -571,6 +626,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
} }
w.fn_by_name(node.name) w.fn_by_name(node.name)
} }
if !w.uses_atomic && node.info is ast.IdentVar {
w.uses_atomic = node.info.typ.has_flag(.atomic_f)
}
} }
} }
w.or_block(node.or_expr) w.or_block(node.or_expr)
@ -587,6 +645,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
if node.has_update_expr { if node.has_update_expr {
w.expr(node.update_expr) w.expr(node.update_expr)
} }
if node.vals.len > 0 && node.has_update_expr {
w.uses_map_update = true
}
mapinfo := w.table.final_sym(node.typ).map_info() mapinfo := w.table.final_sym(node.typ).map_info()
ksym := w.table.sym(mapinfo.key_type) ksym := w.table.sym(mapinfo.key_type)
vsym := w.table.sym(mapinfo.value_type) vsym := w.table.sym(mapinfo.value_type)
@ -596,6 +657,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.mark_by_sym(ksym) w.mark_by_sym(ksym)
w.mark_by_sym(vsym) w.mark_by_sym(vsym)
w.features.used_maps++ w.features.used_maps++
w.mark_by_type(node.typ)
} }
ast.MatchExpr { ast.MatchExpr {
w.expr(node.cond) w.expr(node.cond)
@ -617,6 +679,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.expr(node.expr) w.expr(node.expr)
} }
ast.PrefixExpr { ast.PrefixExpr {
if !w.uses_memdup && node.op == .amp {
w.uses_memdup = true
}
w.expr(node.right) w.expr(node.right)
} }
ast.PostfixExpr { ast.PostfixExpr {
@ -635,7 +700,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.mark_by_type(node.typ) w.mark_by_type(node.typ)
} }
ast.StringInterLiteral { ast.StringInterLiteral {
w.used_interp++ w.uses_interp = true
w.exprs(node.exprs) w.exprs(node.exprs)
} }
ast.SelectorExpr { ast.SelectorExpr {
@ -657,6 +722,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.expr(node.limit_expr) w.expr(node.limit_expr)
w.expr(node.where_expr) w.expr(node.where_expr)
w.mark_by_type(node.typ) w.mark_by_type(node.typ)
w.uses_orm = true
} }
ast.StructInit { ast.StructInit {
if node.typ == 0 { if node.typ == 0 {
@ -730,6 +796,13 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
if node == unsafe { nil } { if node == unsafe { nil } {
return return
} }
if w.level == 0 {
last_is_builtin_mod := w.is_builtin_mod
w.is_builtin_mod = node.mod in ['builtin', 'os', 'strconv', 'builtin.closure']
defer {
w.is_builtin_mod = last_is_builtin_mod
}
}
if node.language == .c { if node.language == .c {
w.mark_fn_as_used(node.fkey()) w.mark_fn_as_used(node.fkey())
w.mark_fn_ret_and_params(node.return_type, node.params) w.mark_fn_ret_and_params(node.return_type, node.params)
@ -742,15 +815,22 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
if node.no_body { if node.no_body {
return return
} }
if w.trace_enabled {
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 { if node.is_method {
w.mark_by_type(node.receiver.typ) w.mark_by_type(node.receiver.typ)
} }
w.mark_fn_ret_and_params(node.return_type, node.params) w.mark_fn_ret_and_params(node.return_type, node.params)
w.mark_fn_as_used(fkey) w.mark_fn_as_used(fkey)
last_is_builtin_mod := w.is_builtin_mod
w.is_builtin_mod = node.mod in ['builtin', 'os', 'strconv', 'builtin.closure']
w.stmts(node.stmts) w.stmts(node.stmts)
w.is_builtin_mod = last_is_builtin_mod
w.defer_stmts(node.defer_stmts) w.defer_stmts(node.defer_stmts)
} }
@ -768,9 +848,7 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
if node.name in ['C.wyhash', 'C.wyhash64'] { if node.name in ['C.wyhash', 'C.wyhash64'] {
w.features.used_maps++ w.features.used_maps++
} }
if node.return_type != 0 { w.mark_by_type(node.return_type)
w.mark_by_type(node.return_type)
}
return return
} }
if node.is_method && node.left_type != 0 { if node.is_method && node.left_type != 0 {
@ -804,6 +882,17 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
fn_embed := '${int(embed_types.last())}.${node.name}' fn_embed := '${int(embed_types.last())}.${node.name}'
w.fn_by_name(fn_embed) w.fn_by_name(fn_embed)
} }
} else {
match left_sym.info {
ast.Array, ast.ArrayFixed {
if !w.uses_arr_void && node.name in ['contains', 'index'] {
if w.table.final_sym(left_sym.info.elem_type).kind == .function {
w.uses_arr_void = true
}
}
}
else {}
}
} }
} }
w.expr(node.left) w.expr(node.left)
@ -844,9 +933,22 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
receiver_typ = node.receiver_concrete_type receiver_typ = node.receiver_concrete_type
w.mark_fn_as_used(fn_name) w.mark_fn_as_used(fn_name)
} }
w.mark_by_type(node.return_type)
stmt := w.all_fns[fn_name] or { return } stmt := w.all_fns[fn_name] or { return }
if !stmt.should_be_skipped && stmt.name == node.name { if !stmt.should_be_skipped && stmt.name == node.name {
if !node.is_method || receiver_typ == stmt.receiver.typ { if !node.is_method || receiver_typ == stmt.receiver.typ {
if w.trace_enabled {
w.level++
defer {
w.level--
}
receiver_name := if node.receiver_type != 0 {
w.table.type_to_str(node.receiver_type) + '.'
} else {
''
}
eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [call]')
}
w.mark_fn_ret_and_params(stmt.return_type, stmt.params) w.mark_fn_ret_and_params(stmt.return_type, stmt.params)
w.stmts(stmt.stmts) w.stmts(stmt.stmts)
} }
@ -863,6 +965,18 @@ pub fn (mut w Walker) fn_by_name(fn_name string) {
return return
} }
stmt := w.all_fns[fn_name] or { return } stmt := w.all_fns[fn_name] or { return }
if w.trace_enabled {
w.level++
defer {
w.level--
}
receiver_name := if fn_name.contains('.') && fn_name.all_before_last('.').int() > 0 {
w.table.type_to_str(fn_name.all_before_last('.').int()) + '.'
} else {
''
}
eprintln('>>>${' '.repeat(w.level)}${receiver_name}${fn_name.all_after_last('.')} [by_name]')
}
w.mark_fn_as_used(fn_name) w.mark_fn_as_used(fn_name)
w.mark_fn_ret_and_params(stmt.return_type, stmt.params) w.mark_fn_ret_and_params(stmt.return_type, stmt.params)
w.stmts(stmt.stmts) w.stmts(stmt.stmts)
@ -873,6 +987,9 @@ pub fn (mut w Walker) struct_fields(sfields []ast.StructField) {
if sf.has_default_expr { if sf.has_default_expr {
w.expr(sf.default_expr) w.expr(sf.default_expr)
} }
if !w.uses_atomic && sf.typ.has_flag(.atomic_f) {
w.uses_atomic = true
}
} }
} }
@ -895,27 +1012,6 @@ pub fn (mut w Walker) or_block(node ast.OrExpr) {
} }
} }
fn (mut w Walker) mark_panic_deps() {
ref_array_idx_str := int(ast.array_type.ref()).str()
string_idx_str := ast.string_type_idx.str()
array_idx_str := ast.array_type_idx.str()
charptr_idx_str := ast.charptr_type_idx.str()
w.fn_by_name('__new_array_with_default')
w.fn_by_name('__new_array_with_default_noscan')
w.fn_by_name('str_intp')
w.fn_by_name(ref_array_idx_str + '.push')
w.fn_by_name(ref_array_idx_str + '.push_noscan')
w.fn_by_name(string_idx_str + '.substr')
w.fn_by_name(array_idx_str + '.slice')
w.fn_by_name(array_idx_str + '.get')
w.fn_by_name('v_fixed_index')
w.fn_by_name(charptr_idx_str + '.vstring_literal')
w.mark_by_sym_name('StrIntpData')
w.mark_by_sym_name('StrIntpMem')
}
pub fn (mut w Walker) mark_fn_ret_and_params(return_type ast.Type, params []ast.Param) { pub fn (mut w Walker) mark_fn_ret_and_params(return_type ast.Type, params []ast.Param) {
if return_type != 0 { if return_type != 0 {
if return_type.has_flag(.option) { if return_type.has_flag(.option) {
@ -930,6 +1026,7 @@ pub fn (mut w Walker) mark_fn_ret_and_params(return_type ast.Type, params []ast.
} }
} }
@[inline]
pub fn (mut w Walker) mark_by_sym_name(name string) { pub fn (mut w Walker) mark_by_sym_name(name string) {
if sym := w.table.find_sym(name) { if sym := w.table.find_sym(name) {
w.mark_by_sym(sym) w.mark_by_sym(sym)
@ -956,7 +1053,7 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
w.expr(ifield.default_expr) w.expr(ifield.default_expr)
} }
if ifield.typ != 0 { if ifield.typ != 0 {
fsym := w.table.sym(ifield.typ) fsym := w.table.sym(ifield.typ.idx())
if ifield.typ.has_flag(.option) { if ifield.typ.has_flag(.option) {
w.used_option++ w.used_option++
if !ifield.has_default_expr { if !ifield.has_default_expr {
@ -964,9 +1061,6 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
} }
} }
match fsym.info { match fsym.info {
ast.Array, ast.ArrayFixed {
w.mark_by_sym(fsym)
}
ast.Map { ast.Map {
w.features.used_maps++ w.features.used_maps++
w.mark_by_sym(fsym) w.mark_by_sym(fsym)
@ -976,17 +1070,26 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
} }
} }
} }
if !w.features.auto_str_ptr && ifield.typ.is_ptr()
&& isym.idx in w.features.print_types {
w.features.auto_str_ptr = true
}
} }
for embed in isym.info.embeds { for embed in isym.info.embeds {
w.mark_by_type(embed) w.mark_by_type(embed)
} }
if decl := w.all_structs[isym.name] { if decl := w.all_structs[isym.name] {
w.struct_fields(decl.fields)
if !w.uses_mem_align {
w.uses_mem_align = decl.attrs.contains('aligned')
}
for iface_typ in decl.implements_types { for iface_typ in decl.implements_types {
w.mark_by_type(iface_typ.typ) w.mark_by_type(iface_typ.typ)
} }
} }
} }
ast.ArrayFixed, ast.Array { ast.ArrayFixed, ast.Array {
w.uses_array = true
w.mark_by_type(isym.info.elem_type) w.mark_by_type(isym.info.elem_type)
} }
ast.SumType { ast.SumType {
@ -1030,6 +1133,13 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
} }
ast.Enum { ast.Enum {
w.mark_by_type(isym.info.typ) w.mark_by_type(isym.info.typ)
if enum_ := w.table.enum_decls[isym.name] {
for field in enum_.fields {
if field.has_expr {
w.expr(field.expr)
}
}
}
} }
ast.Interface { ast.Interface {
for typ in isym.info.types { for typ in isym.info.types {
@ -1037,6 +1147,17 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
w.features.used_maps++ w.features.used_maps++
} }
w.mark_by_type(typ) w.mark_by_type(typ)
for method in isym.info.methods {
for ityp in [typ.set_nr_muls(1), typ.set_nr_muls(0)] {
mname := int(ityp.clear_flags()).str() + '.' + method.name
w.fn_by_name(mname)
}
}
for embed_method in w.table.get_embed_methods(w.table.sym(typ)) {
mname := int(embed_method.params[0].typ.clear_flags()).str() + '.' +
embed_method.name
w.fn_by_name(mname)
}
} }
for embed in isym.info.embeds { for embed in isym.info.embeds {
w.mark_by_type(embed) w.mark_by_type(embed)
@ -1053,6 +1174,9 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
w.mark_fn_ret_and_params(method.return_type, method.params) w.mark_fn_ret_and_params(method.return_type, method.params)
} }
} }
ast.Thread {
w.mark_by_type(isym.info.return_type)
}
else {} else {}
} }
} }
@ -1087,6 +1211,17 @@ fn (mut w Walker) remove_unused_dump_type() {
} }
fn (mut w Walker) mark_resource_dependencies() { fn (mut w Walker) mark_resource_dependencies() {
if w.trace_enabled {
eprintln('>>>>>>>>>> DEPS USAGE')
}
if w.uses_eq {
w.fn_by_name('fast_string_eq')
}
if w.features.auto_str_ptr {
w.fn_by_name('isnil')
w.fn_by_name('tos4')
w.fn_by_name('str_intp')
}
if w.uses_channel { if w.uses_channel {
w.fn_by_name('sync.new_channel_st') w.fn_by_name('sync.new_channel_st')
w.fn_by_name('sync.channel_select') w.fn_by_name('sync.channel_select')
@ -1094,6 +1229,28 @@ fn (mut w Walker) mark_resource_dependencies() {
if w.uses_lock { if w.uses_lock {
w.mark_by_sym_name('sync.RwMutex') w.mark_by_sym_name('sync.RwMutex')
} }
if w.uses_array {
if w.pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt] {
w.fn_by_name('__new_array_noscan')
w.fn_by_name('new_array_from_c_array_noscan')
w.fn_by_name('__new_array_with_multi_default_noscan')
w.fn_by_name('__new_array_with_array_default_noscan')
w.fn_by_name('__new_array_with_default_noscan')
}
w.fn_by_name('__new_array')
w.fn_by_name('new_array_from_c_array')
w.fn_by_name('__new_array_with_multi_default')
w.fn_by_name('__new_array_with_array_default')
w.fn_by_name('__new_array_with_default')
w.fn_by_name(int(ast.array_type.ref()).str() + '.set')
}
if w.uses_orm {
w.fn_by_name('__new_array_with_default_noscan')
w.fn_by_name('new_array_from_c_array')
w.fn_by_name('__new_array')
w.fn_by_name('${ast.array_type_idx}.get')
w.fn_by_name(int(ast.array_type.ref()).str() + '.push')
}
if w.uses_ct_fields { if w.uses_ct_fields {
w.mark_by_sym_name('FieldData') w.mark_by_sym_name('FieldData')
} }
@ -1112,14 +1269,91 @@ fn (mut w Walker) mark_resource_dependencies() {
if w.uses_ct_attribute { if w.uses_ct_attribute {
w.mark_by_sym_name('VAttribute') w.mark_by_sym_name('VAttribute')
} }
if w.uses_map_update {
w.fn_by_name('new_map_update_init')
}
if w.uses_mem_align {
w.fn_by_name('memdup_align')
}
if w.uses_guard {
w.fn_by_name('error')
}
if w.uses_dump {
w.fn_by_name('eprint')
w.fn_by_name('eprintln')
}
if w.uses_spawn {
w.fn_by_name('malloc')
w.fn_by_name('tos3')
}
if w.uses_memdup {
w.fn_by_name('memdup')
}
if w.uses_debugger {
w.mark_by_type(w.table.find_or_register_map(ast.string_type, ast.string_type))
}
if w.uses_arr_void {
w.mark_by_type(w.table.find_or_register_array(ast.voidptr_type))
}
if w.trace_enabled {
types := w.table.used_features.print_types.keys().map(w.table.type_to_str(it))
eprintln('>>>>>>>>>> PRINT TYPES ${types}')
}
for typ, _ in w.table.used_features.print_types {
w.mark_by_type(typ)
}
if w.trace_enabled {
eprintln('>>>>>>>>>> ALL_FNS LOOP')
}
mut has_ptr_print := false
has_str_call := w.uses_interp || w.uses_asserts || w.uses_str || w.features.print_types.len > 0
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 {
w.fn_by_name(k)
if !has_ptr_print && func.receiver.typ.is_ptr() {
w.fn_by_name('ptr_str')
has_ptr_print = true
}
}
continue
}
if w.pref.autofree || (w.uses_free && k.ends_with('.free')
&& func.receiver.typ.idx() in w.used_syms) {
w.fn_by_name(k)
continue
}
if w.uses_atomic && k.starts_with('_Atomic') {
w.fn_by_name(k)
continue
}
if func.name in ['+', '-', '*', '%', '/', '<', '=='] {
if func.receiver.typ.idx() in w.used_syms {
w.fn_by_name(k)
}
continue
}
if !func.is_static_type_method && func.receiver.typ != ast.void_type
&& func.generic_names.len > 0 {
if func.receiver.typ.set_nr_muls(0) in w.table.used_features.comptime_syms
|| func.receiver.typ in w.table.used_features.comptime_syms {
w.fn_by_name(k)
continue
}
}
}
} }
pub fn (mut w Walker) finalize(include_panic_deps bool) { pub fn (mut w Walker) finalize(include_panic_deps bool) {
if include_panic_deps || w.used_interp > 0 || w.uses_external_type {
w.mark_panic_deps()
}
w.mark_resource_dependencies() w.mark_resource_dependencies()
if w.trace_enabled {
eprintln('>>>>>>>>>> FINALIZE')
}
if w.uses_asserts {
w.fn_by_name('__print_assert_failure')
w.fn_by_name('isnil')
w.mark_by_sym_name('VAssertMetaInfo')
}
if w.used_panic > 0 { if w.used_panic > 0 {
w.mark_fn_as_used('panic_option_not_set') w.mark_fn_as_used('panic_option_not_set')
w.mark_fn_as_used('panic_result_not_set') w.mark_fn_as_used('panic_result_not_set')
@ -1140,13 +1374,50 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) {
if (w.used_option + w.used_result + w.used_none) > 0 { if (w.used_option + w.used_result + w.used_none) > 0 {
w.mark_const_as_used('none__') w.mark_const_as_used('none__')
} }
w.mark_by_sym_name('array') if include_panic_deps || w.uses_external_type || w.uses_asserts || w.uses_debugger
|| w.uses_interp {
if w.trace_enabled {
println('>>>>> PANIC DEPS ${include_panic_deps} | external_type=${w.uses_external_type} | asserts=${w.uses_asserts} | dbg=${w.uses_debugger}')
}
ref_array_idx_str := int(ast.array_type.ref()).str()
string_idx_str := ast.string_type_idx.str()
if w.table.used_features.asserts { if w.pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt] {
w.mark_by_sym_name('VAssertMetaInfo') w.fn_by_name('__new_array_with_default_noscan')
w.fn_by_name(ref_array_idx_str + '.push_noscan')
}
w.fn_by_name('str_intp')
w.fn_by_name('__new_array_with_default')
w.fn_by_name(ref_array_idx_str + '.push')
w.fn_by_name(string_idx_str + '.substr')
w.fn_by_name('v_fixed_index')
w.mark_by_sym_name('StrIntpData')
w.mark_by_sym_name('StrIntpMem')
} }
// remove unused symbols // remove unused symbols
w.remove_unused_fn_generic_types() w.remove_unused_fn_generic_types()
w.remove_unused_dump_type() w.remove_unused_dump_type()
if w.trace_enabled {
syms := w.used_syms.keys().map(w.table.type_to_str(it))
eprintln('>>>>>>>>>> USED SYMS ${syms}')
}
}
pub fn (mut w Walker) mark_generic_types() {
if w.trace_enabled {
eprintln('>>>>>>>>>> COMPTIME SYMS+CALLS')
}
for k, _ in w.table.used_features.comptime_calls {
w.fn_by_name(k)
}
for k, _ in w.table.used_features.comptime_syms {
sym := w.table.sym(k)
w.mark_by_sym(sym)
for method in sym.get_methods() {
w.fn_by_name('${k}.${method.name}')
}
}
} }

View file

@ -22,6 +22,8 @@ pub fn (t &ResolverInfo) has_comptime_expr(node ast.Expr) bool {
&& node.init_fields.any(it.expr is ast.AnonFn && it.expr.decl.generic_names.len > 0)) && node.init_fields.any(it.expr is ast.AnonFn && it.expr.decl.generic_names.len > 0))
|| (node is ast.PostfixExpr && t.has_comptime_expr(node.expr)) || (node is ast.PostfixExpr && t.has_comptime_expr(node.expr))
|| (node is ast.SelectorExpr && t.has_comptime_expr(node.expr)) || (node is ast.SelectorExpr && t.has_comptime_expr(node.expr))
|| (node is ast.ArrayInit && node.elem_type.has_flag(.generic))
|| (node is ast.MapInit && node.typ.has_flag(.generic))
|| (node is ast.InfixExpr && (t.has_comptime_expr(node.left) || (node is ast.InfixExpr && (t.has_comptime_expr(node.left)
|| t.has_comptime_expr(node.right))) || t.has_comptime_expr(node.right)))
} }