markused: improve the tracking of used closures (#25009)

This commit is contained in:
Delyan Angelov 2025-07-31 20:41:43 +03:00 committed by GitHub
parent ac00d441ad
commit 5ec3cc17e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 18 additions and 5 deletions

View File

@ -605,6 +605,7 @@ fn (t Tree) fn_decl(node ast.FnDecl) &Node {
obj.add_terse('is_unsafe', t.bool_node(node.is_unsafe))
obj.add_terse('is_markused', t.bool_node(node.is_markused))
obj.add_terse('is_file_translated', t.bool_node(node.is_file_translated))
obj.add_terse('is_closure', t.bool_node(node.is_closure))
obj.add_terse('receiver', t.struct_field(node.receiver))
obj.add('receiver_pos', t.pos(node.receiver_pos))
obj.add_terse('is_method', t.bool_node(node.is_method))

View File

@ -573,7 +573,7 @@ pub:
pub struct AnonFn {
pub mut:
decl FnDecl
inherited_vars []Param
inherited_vars []Param // note: closures have inherited_vars.len > 0
typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
has_gen map[string]bool // a map of the names of all generic anon functions, generated from it
}
@ -602,6 +602,7 @@ pub:
is_must_use bool // true, when @[must_use] is used on a fn. Calls to such functions, that ignore the return value, will cause warnings.
is_markused bool // true, when an explicit `@[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
is_file_translated bool // true, when the file it resides in is `@[translated]`
is_closure bool // true, for actual closures like `fn [inherited] () {}` . It is false for normal anonymous functions, and for named functions/methods too.
receiver StructField // TODO: this is not a struct field
receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position
is_method bool

View File

@ -35,6 +35,7 @@ pub mut:
used_veb_types []Type // veb context types, filled in by checker
used_maps int // how many times maps were used, filled in by markused
used_none int // how many times `none` was used, filled in by markused
used_closures int // number of used closures, either directly with `fn [state] () {}`, or indirectly (though `instance.method` promotions)
// json bool // json is imported
comptime_calls map[string]bool // resolved name to call on comptime
comptime_syms map[Type]bool // resolved syms (generic)

View File

@ -363,13 +363,15 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
table.used_features.used_consts = walker.used_consts.move()
table.used_features.used_globals = walker.used_globals.move()
table.used_features.used_syms = walker.used_syms.move()
table.used_features.used_closures = walker.used_closures
if trace_skip_unused {
eprintln('>> t.used_fns: ${table.used_features.used_fns.keys()}')
eprintln('>> t.used_consts: ${table.used_features.used_consts.keys()}')
eprintln('>> t.used_globals: ${table.used_features.used_globals.keys()}')
eprintln('>> t.used_syms: ${table.used_features.used_syms.keys()}')
eprintln('>> walker.table.used_features.used_maps: ${walker.table.used_features.used_maps}')
eprintln('>> t.used_maps: ${table.used_features.used_maps}')
eprintln('>> t.used_closures: ${table.used_features.used_closures}')
}
if trace_skip_unused_just_unused_fns {
all_fns_keys := all_fns.keys()

View File

@ -21,6 +21,7 @@ pub mut:
used_option int // _option_ok
used_result int // _result_ok
used_panic int // option/result propagation
used_closures int // fn [x] (){}, and `instance.method` used in an expression
pref &pref.Preferences = unsafe { nil }
mut:
all_fns map[string]ast.FnDecl
@ -712,6 +713,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
}
w.mark_by_type(node.typ)
w.or_block(node.or_block)
if node.has_hidden_receiver {
w.used_closures++
}
}
ast.SqlExpr {
w.expr(node.db_expr)
@ -811,9 +815,6 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
if w.used_fns[fkey] {
return
}
if node.no_body {
return
}
if w.trace_enabled {
w.level++
defer { w.level-- }
@ -824,6 +825,12 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
}
eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [decl]')
}
if node.is_closure {
w.used_closures++
}
if node.no_body {
return
}
if node.is_method {
w.mark_by_type(node.receiver.typ)
}

View File

@ -914,6 +914,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
return_type_pos: return_type_pos
params: params
is_variadic: is_variadic
is_closure: inherited_vars.len > 0
is_method: false
generic_names: generic_names
is_anon: true