diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 602b4753a0..9110dffd82 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -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)) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 6d49a84d66..47decb8b57 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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 diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index f962fcfcc2..967c25eeec 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -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) diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index c78b7061b5..f2b5fd6fe7 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -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() diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index e9ce833eec..067e52fa38 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -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) } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 3ce9356817..58f0ecbf28 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -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