Skip to content

Commit 5ec3cc1

Browse files
authored
markused: improve the tracking of used closures (#25009)
1 parent ac00d44 commit 5ec3cc1

6 files changed

Lines changed: 18 additions & 5 deletions

File tree

‎cmd/tools/vast/vast.v‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ fn (t Tree) fn_decl(node ast.FnDecl) &Node {
605605
obj.add_terse('is_unsafe', t.bool_node(node.is_unsafe))
606606
obj.add_terse('is_markused', t.bool_node(node.is_markused))
607607
obj.add_terse('is_file_translated', t.bool_node(node.is_file_translated))
608+
obj.add_terse('is_closure', t.bool_node(node.is_closure))
608609
obj.add_terse('receiver', t.struct_field(node.receiver))
609610
obj.add('receiver_pos', t.pos(node.receiver_pos))
610611
obj.add_terse('is_method', t.bool_node(node.is_method))

‎vlib/v/ast/ast.v‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ pub:
573573
pub struct AnonFn {
574574
pub mut:
575575
decl FnDecl
576-
inherited_vars []Param
576+
inherited_vars []Param // note: closures have inherited_vars.len > 0
577577
typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
578578
has_gen map[string]bool // a map of the names of all generic anon functions, generated from it
579579
}
@@ -602,6 +602,7 @@ pub:
602602
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.
603603
is_markused bool // true, when an explicit `@[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
604604
is_file_translated bool // true, when the file it resides in is `@[translated]`
605+
is_closure bool // true, for actual closures like `fn [inherited] () {}` . It is false for normal anonymous functions, and for named functions/methods too.
605606
receiver StructField // TODO: this is not a struct field
606607
receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position
607608
is_method bool

‎vlib/v/ast/table.v‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub mut:
3535
used_veb_types []Type // veb context types, filled in by checker
3636
used_maps int // how many times maps were used, filled in by markused
3737
used_none int // how many times `none` was used, filled in by markused
38+
used_closures int // number of used closures, either directly with `fn [state] () {}`, or indirectly (though `instance.method` promotions)
3839
// json bool // json is imported
3940
comptime_calls map[string]bool // resolved name to call on comptime
4041
comptime_syms map[Type]bool // resolved syms (generic)

‎vlib/v/markused/markused.v‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,15 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
363363
table.used_features.used_consts = walker.used_consts.move()
364364
table.used_features.used_globals = walker.used_globals.move()
365365
table.used_features.used_syms = walker.used_syms.move()
366+
table.used_features.used_closures = walker.used_closures
366367

367368
if trace_skip_unused {
368369
eprintln('>> t.used_fns: ${table.used_features.used_fns.keys()}')
369370
eprintln('>> t.used_consts: ${table.used_features.used_consts.keys()}')
370371
eprintln('>> t.used_globals: ${table.used_features.used_globals.keys()}')
371372
eprintln('>> t.used_syms: ${table.used_features.used_syms.keys()}')
372-
eprintln('>> walker.table.used_features.used_maps: ${walker.table.used_features.used_maps}')
373+
eprintln('>> t.used_maps: ${table.used_features.used_maps}')
374+
eprintln('>> t.used_closures: ${table.used_features.used_closures}')
373375
}
374376
if trace_skip_unused_just_unused_fns {
375377
all_fns_keys := all_fns.keys()

‎vlib/v/markused/walker.v‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mut:
2121
used_option int // _option_ok
2222
used_result int // _result_ok
2323
used_panic int // option/result propagation
24+
used_closures int // fn [x] (){}, and `instance.method` used in an expression
2425
pref &pref.Preferences = unsafe { nil }
2526
mut:
2627
all_fns map[string]ast.FnDecl
@@ -712,6 +713,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
712713
}
713714
w.mark_by_type(node.typ)
714715
w.or_block(node.or_block)
716+
if node.has_hidden_receiver {
717+
w.used_closures++
718+
}
715719
}
716720
ast.SqlExpr {
717721
w.expr(node.db_expr)
@@ -811,9 +815,6 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
811815
if w.used_fns[fkey] {
812816
return
813817
}
814-
if node.no_body {
815-
return
816-
}
817818
if w.trace_enabled {
818819
w.level++
819820
defer { w.level-- }
@@ -824,6 +825,12 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
824825
}
825826
eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [decl]')
826827
}
828+
if node.is_closure {
829+
w.used_closures++
830+
}
831+
if node.no_body {
832+
return
833+
}
827834
if node.is_method {
828835
w.mark_by_type(node.receiver.typ)
829836
}

‎vlib/v/parser/fn.v‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
914914
return_type_pos: return_type_pos
915915
params: params
916916
is_variadic: is_variadic
917+
is_closure: inherited_vars.len > 0
917918
is_method: false
918919
generic_names: generic_names
919920
is_anon: true

0 commit comments

Comments
 (0)