mirror of
https://github.com/vlang/v.git
synced 2025-08-03 09:47:15 -04:00
markused: skip unused symbols, dump fns and generic specialization (fix #24921) (fix #24927) (#24924)
This commit is contained in:
parent
938f462daf
commit
ae1fa8aced
@ -12,6 +12,7 @@ import v.util.version
|
||||
import v.builder
|
||||
import v.builder.cbuilder
|
||||
|
||||
@[markused]
|
||||
const external_tools = [
|
||||
'ast',
|
||||
'bin2v',
|
||||
|
@ -32,6 +32,7 @@ pub:
|
||||
thickness f32 = 1
|
||||
}
|
||||
|
||||
@[markused]
|
||||
pub struct Size {
|
||||
pub mut:
|
||||
width int
|
||||
|
@ -9,7 +9,7 @@ import sokol.sgl
|
||||
|
||||
// Image holds the fields and data needed to
|
||||
// represent a bitmap/pixel based image in memory.
|
||||
@[heap]
|
||||
@[heap; markused]
|
||||
pub struct Image {
|
||||
pub mut:
|
||||
id int
|
||||
|
@ -112,6 +112,7 @@ pub const light_red = Color{
|
||||
}
|
||||
|
||||
// Color represents a 32 bit color value in sRGB format
|
||||
@[markused]
|
||||
pub struct Color {
|
||||
pub mut:
|
||||
r u8
|
||||
|
@ -4,7 +4,7 @@ module gx
|
||||
pub const align_left = HorizontalAlign.left
|
||||
pub const align_right = HorizontalAlign.right
|
||||
|
||||
@[params]
|
||||
@[markused; params]
|
||||
pub struct TextCfg {
|
||||
pub:
|
||||
color Color = black
|
||||
|
@ -9,6 +9,7 @@ $if freebsd || openbsd {
|
||||
#include <sys/sysctl.h>
|
||||
}
|
||||
|
||||
@[markused]
|
||||
pub const args = arguments()
|
||||
|
||||
fn C.readdir(voidptr) &C.dirent
|
||||
|
@ -453,6 +453,7 @@ pub:
|
||||
pub mut:
|
||||
language Language
|
||||
fields []StructField
|
||||
idx int
|
||||
}
|
||||
|
||||
pub struct Embed {
|
||||
@ -1484,6 +1485,7 @@ pub:
|
||||
comments []Comment
|
||||
pub mut:
|
||||
parent_type Type
|
||||
is_markused bool
|
||||
}
|
||||
|
||||
// SumTypeDecl is the ast node for `type MySumType = string | int`
|
||||
@ -1497,7 +1499,8 @@ pub:
|
||||
generic_types []Type
|
||||
attrs []Attr // attributes of type declaration
|
||||
pub mut:
|
||||
variants []TypeNode
|
||||
variants []TypeNode
|
||||
is_markused bool
|
||||
}
|
||||
|
||||
pub struct FnTypeDecl {
|
||||
@ -1510,6 +1513,7 @@ pub:
|
||||
comments []Comment
|
||||
generic_types []Type
|
||||
attrs []Attr // attributes of type declaration
|
||||
is_markused bool
|
||||
}
|
||||
|
||||
// TODO: handle this differently
|
||||
|
@ -34,6 +34,7 @@ pub mut:
|
||||
used_fns map[string]bool // filled in by markused
|
||||
used_consts map[string]bool // filled in by markused
|
||||
used_globals map[string]bool // filled in by markused
|
||||
used_syms map[int]bool // filled in by markused
|
||||
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_arrays int // how many times arrays were used, filled in by markused
|
||||
@ -42,6 +43,7 @@ pub mut:
|
||||
// json bool // json is imported
|
||||
debugger bool // debugger is used
|
||||
comptime_calls map[string]bool // resolved name to call on comptime
|
||||
comptime_syms map[int]bool // resolved syms (generic)
|
||||
comptime_for bool // uses $for
|
||||
memory_align bool // @[aligned] for struct
|
||||
}
|
||||
|
@ -183,6 +183,7 @@ pub mut:
|
||||
is_anon bool
|
||||
is_generic bool
|
||||
is_shared bool
|
||||
is_markused bool
|
||||
has_option bool // contains any option field
|
||||
generic_types []Type
|
||||
concrete_types []Type
|
||||
|
@ -3137,6 +3137,10 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
|
||||
c.inside_if_guard = true
|
||||
node.expr_type = c.expr(mut node.expr)
|
||||
c.inside_if_guard = old_inside_if_guard
|
||||
if c.pref.skip_unused && node.expr_type.has_flag(.generic) {
|
||||
unwrapped_type := c.unwrap_generic(node.expr_type)
|
||||
c.table.used_features.comptime_syms[unwrapped_type] = true
|
||||
}
|
||||
if !node.expr_type.has_flag(.option) && !node.expr_type.has_flag(.result) {
|
||||
mut no_opt_or_res := true
|
||||
match mut node.expr {
|
||||
@ -3435,6 +3439,9 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||
// allow conversion from none to every option type
|
||||
} else if to_sym.kind == .sum_type {
|
||||
to_sym_info := to_sym.info as ast.SumType
|
||||
if c.pref.skip_unused && to_sym_info.concrete_types.len > 0 {
|
||||
c.table.used_features.comptime_syms[to_type] = true
|
||||
}
|
||||
if to_sym_info.generic_types.len > 0 && to_sym_info.concrete_types.len == 0 {
|
||||
c.error('generic sumtype `${to_sym.name}` must specify type parameter, e.g. ${to_sym.name}[int]',
|
||||
node.pos)
|
||||
@ -5227,6 +5234,9 @@ fn (mut c Checker) chan_init(mut node ast.ChanInit) ast.Type {
|
||||
if node.has_cap {
|
||||
c.check_array_init_para_type('cap', mut node.cap_expr, node.pos)
|
||||
}
|
||||
if c.pref.skip_unused && node.typ.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
|
||||
}
|
||||
return node.typ
|
||||
} else {
|
||||
c.error('`chan` of unknown type', node.pos)
|
||||
|
@ -339,6 +339,14 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.pref.skip_unused {
|
||||
if param.typ.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[c.unwrap_generic(param.typ)] = true
|
||||
}
|
||||
if node.return_type.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[c.unwrap_generic(node.return_type)] = true
|
||||
}
|
||||
}
|
||||
if param.name == node.mod && param.name != 'main' {
|
||||
c.error('duplicate of a module name `${param.name}`', param.pos)
|
||||
}
|
||||
@ -992,6 +1000,9 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||
}
|
||||
typ := expr as ast.TypeNode
|
||||
node.return_type = if is_json_decode { typ.typ.set_flag(.result) } else { typ.typ }
|
||||
if typ.typ.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[c.unwrap_generic(typ.typ)] = true
|
||||
}
|
||||
return node.return_type
|
||||
} else if fn_name == '__addr' {
|
||||
if !c.inside_unsafe {
|
||||
@ -1859,6 +1870,11 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.pref.skip_unused && node.concrete_types.len > 0 {
|
||||
for concrete_type in node.concrete_types {
|
||||
c.table.used_features.comptime_syms[c.unwrap_generic(concrete_type)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resolve return generics struct to concrete type
|
||||
@ -1877,6 +1893,9 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||
if typ := c.table.convert_generic_type(func.return_type, func.generic_names, concrete_types) {
|
||||
node.return_type = typ
|
||||
c.register_trace_call(node, func)
|
||||
if func.return_type.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[typ.clear_option_and_result()] = true
|
||||
}
|
||||
return typ
|
||||
}
|
||||
}
|
||||
@ -1889,6 +1908,12 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||
ret_type := c.resolve_fn_return_type(func, node, concrete_types)
|
||||
c.register_trace_call(node, func)
|
||||
node.return_type = ret_type
|
||||
if ret_type.has_flag(.generic) {
|
||||
unwrapped_ret := c.unwrap_generic(ret_type)
|
||||
if c.table.sym(unwrapped_ret).kind == .multi_return {
|
||||
c.table.used_features.comptime_syms[unwrapped_ret] = true
|
||||
}
|
||||
}
|
||||
return ret_type
|
||||
}
|
||||
c.register_trace_call(node, func)
|
||||
|
@ -72,6 +72,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||
expected_types = expected_type_sym.info.types.clone()
|
||||
if c.table.cur_concrete_types.len > 0 {
|
||||
expected_types = expected_types.map(c.unwrap_generic(it))
|
||||
c.table.used_features.comptime_syms[c.table.find_or_register_multi_return(expected_types)] = true
|
||||
}
|
||||
}
|
||||
mut got_types := []ast.Type{}
|
||||
@ -226,6 +227,9 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if c.pref.skip_unused && got_types[i].has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[got_type] = true
|
||||
}
|
||||
if exp_type_sym.kind == .interface {
|
||||
if c.type_implements(got_type, exp_type, node.pos) {
|
||||
if !got_type.is_any_kind_of_pointer() && got_type_sym.kind != .interface
|
||||
|
@ -17,6 +17,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
|
||||
}
|
||||
node_name := if node.scoped_name != '' { node.scoped_name } else { node.name }
|
||||
mut struct_sym, struct_typ_idx := c.table.find_sym_and_type_idx(node_name)
|
||||
node.idx = struct_typ_idx
|
||||
mut has_generic_types := false
|
||||
if mut struct_sym.info is ast.Struct {
|
||||
for mut symfield in struct_sym.info.fields {
|
||||
@ -534,6 +535,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
|
||||
if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 {
|
||||
c.table.unwrap_generic_type_ex(node.typ, c.table.cur_fn.generic_names, c.table.cur_concrete_types,
|
||||
true)
|
||||
if c.pref.skip_unused && node.typ.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
|
||||
}
|
||||
}
|
||||
if !is_field_zero_struct_init {
|
||||
c.ensure_type_exists(node.typ, node.pos)
|
||||
|
@ -27,7 +27,11 @@ 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') {
|
||||
unwrapped_type := c.unwrap_generic(node.expr_type)
|
||||
if node.expr_type.has_flag(.generic) {
|
||||
c.table.used_features.comptime_syms[unwrapped_type] = true
|
||||
}
|
||||
if !c.table.sym(unwrapped_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
|
||||
|
@ -623,9 +623,13 @@ fn (mut g Gen) gen_interface_equality_fn(left_type ast.Type) string {
|
||||
fn_builder.writeln('\t\tint idx = v_typeof_interface_idx_${idx_fn}(${left_arg});')
|
||||
if info is ast.Interface {
|
||||
for typ in info.types {
|
||||
sym := g.table.sym(typ.set_nr_muls(0))
|
||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
fn_builder.writeln('\t\tif (idx == ${typ.idx()}) {')
|
||||
fn_builder.write_string('\t\t\treturn ')
|
||||
match g.table.type_kind(typ.set_nr_muls(0)) {
|
||||
match sym.kind {
|
||||
.struct {
|
||||
eq_fn := g.gen_struct_equality_fn(typ)
|
||||
l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
|
||||
|
@ -409,6 +409,9 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, typ_str st
|
||||
fn_builder.writeln('${g.static_non_parallel}string indent_${str_fn_name}(${styp} x, int indent_count) { /* gen_str_for_interface */')
|
||||
for typ in info.types {
|
||||
sub_sym := g.table.sym(ast.mktyp(typ))
|
||||
if g.pref.skip_unused && sub_sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
mut func_name := g.get_str_fn(typ)
|
||||
sym_has_str_method, str_method_expects_ptr, _ := sub_sym.str_method_info()
|
||||
if should_use_indent_func(sub_sym.kind) && !sym_has_str_method {
|
||||
|
@ -1120,6 +1120,9 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||
g.writeln('// >> typeof() support for sum types / interfaces')
|
||||
for ityp, sym in g.table.type_symbols {
|
||||
if sym.kind == .sum_type {
|
||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
static_prefix := if g.pref.build_mode == .build_module { 'static ' } else { '' }
|
||||
sum_info := sym.info as ast.SumType
|
||||
if sum_info.is_generic {
|
||||
@ -1192,6 +1195,10 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||
if sub_sym.info is ast.Struct && sub_sym.info.is_unresolved_generic() {
|
||||
continue
|
||||
}
|
||||
if g.pref.skip_unused && sub_sym.kind == .struct
|
||||
&& sub_sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
g.writeln('\tif (sidx == _${sym.cname}_${sub_sym.cname}_index) return "${util.strip_main_name(sub_sym.name)}";')
|
||||
}
|
||||
g.writeln2('\treturn "unknown ${util.strip_main_name(sym.name)}";', '}')
|
||||
@ -1205,6 +1212,10 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||
if sub_sym.info is ast.Struct && sub_sym.info.is_unresolved_generic() {
|
||||
continue
|
||||
}
|
||||
if g.pref.skip_unused && sub_sym.kind == .struct
|
||||
&& sub_sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
g.writeln('\tif (sidx == _${sym.cname}_${sub_sym.cname}_index) return ${int(t.set_nr_muls(0))};')
|
||||
}
|
||||
g.writeln2('\treturn ${int(ityp)};', '}')
|
||||
@ -1768,6 +1779,9 @@ static inline void __${sym.cname}_pushval(${sym.cname} ch, ${push_arg} val) {
|
||||
}
|
||||
for sym in g.table.type_symbols {
|
||||
if sym.kind == .alias && !sym.is_builtin && sym.name !in ['byte', 'i32'] {
|
||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
g.write_alias_typesymbol_declaration(sym)
|
||||
}
|
||||
}
|
||||
@ -1864,7 +1878,11 @@ pub fn (mut g Gen) write_interface_typesymbol_declaration(sym ast.TypeSymbol) {
|
||||
if mk_typ != variant && mk_typ in info.types {
|
||||
continue
|
||||
}
|
||||
vcname := g.table.sym(mk_typ).cname
|
||||
vsym := g.table.sym(mk_typ)
|
||||
if g.pref.skip_unused && vsym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
vcname := vsym.cname
|
||||
g.type_definitions.writeln('\t\t${vcname}* _${vcname};')
|
||||
}
|
||||
g.type_definitions.writeln('\t};')
|
||||
@ -1883,6 +1901,11 @@ pub fn (mut g Gen) write_fn_typesymbol_declaration(sym ast.TypeSymbol) {
|
||||
is_fn_sig := func.name == ''
|
||||
not_anon := !info.is_anon
|
||||
mut has_generic_arg := false
|
||||
|
||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||
return
|
||||
}
|
||||
|
||||
for param in func.params {
|
||||
if param.typ.has_flag(.generic) {
|
||||
has_generic_arg = true
|
||||
@ -1965,6 +1988,9 @@ pub fn (mut g Gen) write_multi_return_types() {
|
||||
if info.types.any(it.has_flag(.generic)) {
|
||||
continue
|
||||
}
|
||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
g.typedefs.writeln('typedef struct ${sym.cname} ${sym.cname};')
|
||||
g.type_definitions.writeln('struct ${sym.cname} {')
|
||||
for i, mr_typ in info.types {
|
||||
@ -2582,6 +2608,10 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
// Register an option if it's not registered yet
|
||||
g.register_option(method.return_type)
|
||||
} else if method.return_type.has_flag(.result) {
|
||||
if g.pref.skip_unused
|
||||
&& g.table.sym(method.return_type).idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
// Register a result if it's not registered yet
|
||||
g.register_result(method.return_type)
|
||||
}
|
||||
@ -2610,6 +2640,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
if node.language == .c {
|
||||
return
|
||||
}
|
||||
if g.pref.skip_unused && node.idx !in g.table.used_features.used_syms {
|
||||
return
|
||||
}
|
||||
if node.is_union {
|
||||
g.typedefs.writeln('typedef union ${name} ${name};')
|
||||
} else {
|
||||
@ -4705,6 +4738,9 @@ fn (mut g Gen) enum_decl(node ast.EnumDecl) {
|
||||
if g.is_cc_msvc {
|
||||
mut last_value := '0'
|
||||
enum_typ_name := g.table.get_type_name(node.typ)
|
||||
if g.pref.skip_unused && node.typ.idx() !in g.table.used_features.used_syms {
|
||||
return
|
||||
}
|
||||
g.enum_typedefs.writeln('')
|
||||
g.enum_typedefs.writeln('typedef ${enum_typ_name} ${enum_name};')
|
||||
for i, field in node.fields {
|
||||
@ -4725,6 +4761,9 @@ fn (mut g Gen) enum_decl(node ast.EnumDecl) {
|
||||
}
|
||||
return
|
||||
}
|
||||
if g.pref.skip_unused && node.typ.idx() !in g.table.used_features.used_syms {
|
||||
return
|
||||
}
|
||||
g.enum_typedefs.writeln('')
|
||||
if node.typ != ast.int_type {
|
||||
g.enum_typedefs.writeln('#pragma pack(push, 1)')
|
||||
@ -6395,6 +6434,9 @@ fn (mut g Gen) write_debug_calls_typeof_functions() {
|
||||
if sum_info.is_generic {
|
||||
continue
|
||||
}
|
||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
g.writeln('\tv_typeof_sumtype_${sym.cname}(0);')
|
||||
}
|
||||
if sym.kind == .interface {
|
||||
@ -6677,6 +6719,9 @@ 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)
|
||||
struct_names[name] = true
|
||||
}
|
||||
@ -6700,7 +6745,8 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
}
|
||||
}
|
||||
ast.SumType {
|
||||
if sym.info.is_generic || struct_names[name] {
|
||||
if sym.info.is_generic || struct_names[name]
|
||||
|| (g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms) {
|
||||
continue
|
||||
}
|
||||
struct_names[name] = true
|
||||
@ -6788,6 +6834,10 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
||||
}
|
||||
g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];')
|
||||
} 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}];')
|
||||
}
|
||||
}
|
||||
@ -7728,6 +7778,10 @@ fn (mut g Gen) register_iface_return_types() {
|
||||
for _, method_name in inter_info.get_methods() {
|
||||
method := isym.find_method_with_generic_parent(method_name) or { continue }
|
||||
if method.return_type.has_flag(.result) {
|
||||
if g.pref.skip_unused
|
||||
&& g.table.sym(method.return_type).idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
g.register_result(method.return_type)
|
||||
}
|
||||
}
|
||||
@ -7760,7 +7814,12 @@ fn (mut g Gen) interface_table() string {
|
||||
for k, method_name in inter_methods {
|
||||
method := isym.find_method_with_generic_parent(method_name) or { continue }
|
||||
methodidx[method.name] = k
|
||||
ret_styp := g.ret_styp(method.return_type)
|
||||
ret_styp := if g.pref.skip_unused
|
||||
&& g.table.sym(method.return_type).idx !in g.table.used_features.used_syms {
|
||||
'void'
|
||||
} else {
|
||||
g.ret_styp(method.return_type)
|
||||
}
|
||||
methods_struct_def.write_string('\t${ret_styp} (*_method_${c_fn_name(method.name)})(void* _')
|
||||
// the first param is the receiver, it's handled by `void*` above
|
||||
for i in 1 .. method.params.len {
|
||||
@ -7803,6 +7862,12 @@ fn (mut g Gen) interface_table() string {
|
||||
// cctype is the Cleaned Concrete Type name, *without ptr*,
|
||||
// i.e. cctype is always just Cat, not Cat_ptr:
|
||||
cctype := g.cc_type(ast.mktyp(st), true)
|
||||
cctype2 := if g.pref.skip_unused && st_sym_info.idx !in g.table.used_features.used_syms {
|
||||
'voidptr'
|
||||
} else {
|
||||
cctype
|
||||
}
|
||||
cctype_param := if cctype == cctype2 { cctype } else { 'void' }
|
||||
$if debug_interface_table ? {
|
||||
eprintln('>> interface name: ${isym.name} | concrete type: ${st.debug()} | st symname: ${st_sym.name}')
|
||||
}
|
||||
@ -7813,43 +7878,47 @@ fn (mut g Gen) interface_table() string {
|
||||
}
|
||||
already_generated_mwrappers[interface_index_name] = current_iinidx
|
||||
current_iinidx++
|
||||
sb.writeln('static ${interface_name} I_${cctype}_to_Interface_${interface_name}(${cctype}* x);')
|
||||
sb.writeln('static ${interface_name} I_${cctype}_to_Interface_${interface_name}(${cctype_param}* x);')
|
||||
mut cast_struct := strings.new_builder(100)
|
||||
cast_struct.writeln('(${interface_name}) {')
|
||||
cast_struct.writeln('\t\t._${cctype} = x,')
|
||||
cast_struct.writeln('\t\t._${cctype2} = x,')
|
||||
cast_struct.writeln('\t\t._typ = ${interface_index_name},')
|
||||
for field in inter_info.fields {
|
||||
cname := c_name(field.name)
|
||||
field_styp := g.styp(field.typ)
|
||||
if _ := st_sym.find_field(field.name) {
|
||||
cast_struct.writeln('\t\t.${cname} = (${field_styp}*)((char*)x + __offsetof_ptr(x, ${cctype}, ${cname})),')
|
||||
} else if st_sym.kind == .array
|
||||
&& field.name in ['element_size', 'data', 'offset', 'len', 'cap', 'flags'] {
|
||||
// Manually checking, we already knows array contains above fields
|
||||
cast_struct.writeln('\t\t.${cname} = (${field_styp}*)((char*)x + __offsetof_ptr(x, ${cctype}, ${cname})),')
|
||||
} else {
|
||||
// the field is embedded in another struct
|
||||
cast_struct.write_string('\t\t.${cname} = (${field_styp}*)((char*)x')
|
||||
if st != ast.voidptr_type && st != ast.nil_type {
|
||||
if st_sym.kind == .struct {
|
||||
if _, embeds := g.table.find_field_from_embeds(st_sym, field.name) {
|
||||
mut typ_name := ''
|
||||
for i, embed in embeds {
|
||||
esym := g.table.sym(embed)
|
||||
if i == 0 {
|
||||
cast_struct.write_string(' + __offsetof_ptr(x, ${cctype}, ${esym.embed_name()})')
|
||||
} else {
|
||||
cast_struct.write_string(' + __offsetof_ptr(x, ${typ_name}, ${esym.embed_name()})')
|
||||
if cctype == cctype2 {
|
||||
for field in inter_info.fields {
|
||||
cname := c_name(field.name)
|
||||
field_styp := g.styp(field.typ)
|
||||
if _ := st_sym.find_field(field.name) {
|
||||
cast_struct.writeln('\t\t.${cname} = (${field_styp}*)((char*)x + __offsetof_ptr(x, ${cctype2}, ${cname})),')
|
||||
} else if st_sym.kind == .array
|
||||
&& field.name in ['element_size', 'data', 'offset', 'len', 'cap', 'flags'] {
|
||||
// Manually checking, we already knows array contains above fields
|
||||
cast_struct.writeln('\t\t.${cname} = (${field_styp}*)((char*)x + __offsetof_ptr(x, ${cctype2}, ${cname})),')
|
||||
} else {
|
||||
// the field is embedded in another struct
|
||||
cast_struct.write_string('\t\t.${cname} = (${field_styp}*)((char*)x')
|
||||
if st != ast.voidptr_type && st != ast.nil_type {
|
||||
if st_sym.kind == .struct {
|
||||
if _, embeds := g.table.find_field_from_embeds(st_sym,
|
||||
field.name)
|
||||
{
|
||||
mut typ_name := ''
|
||||
for i, embed in embeds {
|
||||
esym := g.table.sym(embed)
|
||||
if i == 0 {
|
||||
cast_struct.write_string(' + __offsetof_ptr(x, ${cctype}, ${esym.embed_name()})')
|
||||
} else {
|
||||
cast_struct.write_string(' + __offsetof_ptr(x, ${typ_name}, ${esym.embed_name()})')
|
||||
}
|
||||
typ_name = esym.cname
|
||||
}
|
||||
if embeds.len > 0 {
|
||||
cast_struct.write_string(' + __offsetof_ptr(x, ${typ_name}, ${cname})')
|
||||
}
|
||||
typ_name = esym.cname
|
||||
}
|
||||
if embeds.len > 0 {
|
||||
cast_struct.write_string(' + __offsetof_ptr(x, ${typ_name}, ${cname})')
|
||||
}
|
||||
}
|
||||
}
|
||||
cast_struct.writeln('),')
|
||||
}
|
||||
cast_struct.writeln('),')
|
||||
}
|
||||
}
|
||||
cast_struct.write_string('\t}')
|
||||
@ -7861,7 +7930,7 @@ fn (mut g Gen) interface_table() string {
|
||||
}
|
||||
|
||||
cast_functions.writeln('
|
||||
static inline ${interface_name} I_${cctype}_to_Interface_${interface_name}(${cctype}* x) {
|
||||
static inline ${interface_name} I_${cctype}_to_Interface_${interface_name}(${cctype_param}* x) {
|
||||
return ${cast_struct_str};
|
||||
}')
|
||||
|
||||
@ -7973,7 +8042,7 @@ return ${cast_shared_struct_str};
|
||||
}
|
||||
styp := g.cc_type(method.params[0].typ, true)
|
||||
mut method_call := '${styp}_${name}'
|
||||
if !method.params[0].typ.is_ptr() {
|
||||
if cctype == cctype2 && !method.params[0].typ.is_ptr() {
|
||||
if method.name !in aliased_method_names {
|
||||
method_call = '${cctype}_${name}'
|
||||
} else {
|
||||
@ -8056,6 +8125,10 @@ return ${cast_shared_struct_str};
|
||||
conversion_functions.write_string('static inline bool I_${interface_name}_is_I_${vsym.cname}(${interface_name} x) {\n\treturn ')
|
||||
for i, variant in variants {
|
||||
variant_sym := g.table.sym(variant)
|
||||
if g.pref.skip_unused && variant_sym.kind == .struct
|
||||
&& variant_sym.idx !in g.table.used_features.used_syms {
|
||||
continue
|
||||
}
|
||||
if i > 0 {
|
||||
conversion_functions.write_string(' || ')
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
// vtest vflags: -cc gcc -os windows
|
||||
|
||||
@[aligned: 8]
|
||||
@[markused]
|
||||
struct Test {
|
||||
a int
|
||||
}
|
||||
|
||||
@[aligned: 16]
|
||||
@[markused]
|
||||
struct Test2 {
|
||||
a int
|
||||
b int
|
||||
}
|
||||
|
||||
@[aligned: 8]
|
||||
@[markused]
|
||||
union Test3 {
|
||||
a int
|
||||
}
|
||||
|
@ -1,17 +1,19 @@
|
||||
// vtest vflags: -cc msvc -os windows
|
||||
|
||||
@[aligned: 8]
|
||||
@[markused]
|
||||
struct Test {
|
||||
a int
|
||||
}
|
||||
|
||||
@[aligned: 16]
|
||||
@[markused]
|
||||
struct Test2 {
|
||||
a int
|
||||
b int
|
||||
}
|
||||
|
||||
@[aligned: 8]
|
||||
@[markused]
|
||||
union Test3 {
|
||||
a int
|
||||
}
|
||||
|
4
vlib/v/gen/c/testdata/aligned_attr_nix.vv
vendored
4
vlib/v/gen/c/testdata/aligned_attr_nix.vv
vendored
@ -1,15 +1,17 @@
|
||||
@[aligned]
|
||||
@[aligned; markused]
|
||||
struct Test {
|
||||
a int
|
||||
}
|
||||
|
||||
@[aligned: 16]
|
||||
@[markused]
|
||||
struct Test2 {
|
||||
a int
|
||||
b int
|
||||
}
|
||||
|
||||
@[aligned: 8]
|
||||
@[markused]
|
||||
union Test3 {
|
||||
a int
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
// vtest vflags: -shared
|
||||
module gdi
|
||||
|
||||
@[markused]
|
||||
pub type Get_proc_address = fn (&i8) &Function_ptr
|
||||
|
||||
@[markused]
|
||||
pub type Set_proc_address = fn (&Function_ptr2)
|
||||
|
||||
@[markused]
|
||||
pub type Function_ptr = fn ()
|
||||
|
||||
@[markused]
|
||||
pub type Function_ptr2 = fn ()
|
||||
|
@ -8,7 +8,7 @@ import v.pref
|
||||
|
||||
// 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) {
|
||||
mut all_fns, all_consts, all_globals, all_fields := all_global_decl(ast_files)
|
||||
mut all_fns, all_consts, all_globals, all_fields, all_decltypes := all_global_decl(ast_files)
|
||||
util.timing_start('MARKUSED')
|
||||
defer {
|
||||
util.timing_measure('MARKUSED')
|
||||
@ -52,7 +52,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
|
||||
println('> used_fn, found matching symbol: ${m}')
|
||||
}
|
||||
}
|
||||
|
||||
if pref_.backend == .native {
|
||||
// Note: this is temporary, until the native backend supports more features!
|
||||
all_fn_root_names << 'main.main'
|
||||
@ -441,25 +440,38 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
|
||||
}
|
||||
|
||||
mut walker := Walker.new(
|
||||
table: table
|
||||
files: ast_files
|
||||
all_fns: all_fns
|
||||
all_consts: all_consts
|
||||
all_globals: all_globals
|
||||
all_fields: all_fields
|
||||
pref: pref_
|
||||
table: table
|
||||
files: ast_files
|
||||
all_fns: all_fns
|
||||
all_consts: all_consts
|
||||
all_globals: all_globals
|
||||
all_fields: all_fields
|
||||
all_decltypes: all_decltypes
|
||||
pref: pref_
|
||||
)
|
||||
walker.mark_markused_consts() // tagged with `@[markused]`
|
||||
walker.mark_markused_globals() // tagged with `@[markused]`
|
||||
walker.mark_markused_syms() // tagged with `@[markused]`
|
||||
walker.mark_markused_fns() // tagged with `@[markused]`, `@[export]` and veb actions
|
||||
walker.mark_markused_decltypes() // tagged with `@[markused]`
|
||||
walker.mark_struct_field_default_expr()
|
||||
|
||||
for k, _ in table.used_features.comptime_calls {
|
||||
walker.fn_by_name(k)
|
||||
// println('>>>>> ${k}')
|
||||
}
|
||||
|
||||
for k, _ in table.used_features.comptime_syms {
|
||||
walker.mark_by_sym(table.sym(k))
|
||||
// println('>>>>> ${k}')
|
||||
}
|
||||
// println(all_fn_root_names)
|
||||
|
||||
walker.mark_root_fns(all_fn_root_names)
|
||||
|
||||
walker.mark_by_sym_name('vweb.RedirectParams')
|
||||
walker.mark_by_sym_name('vweb.RequestParams')
|
||||
|
||||
if table.used_features.used_maps > 0 {
|
||||
for k, mut mfn in all_fns {
|
||||
mut method_receiver_typename := ''
|
||||
@ -516,17 +528,25 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
|
||||
}
|
||||
if walker.used_none > 0 || table.used_features.auto_str {
|
||||
walker.mark_fn_as_used('_option_none')
|
||||
walker.mark_by_sym_name('_option')
|
||||
}
|
||||
if walker.used_option > 0 {
|
||||
walker.mark_fn_as_used('_option_clone')
|
||||
walker.mark_fn_as_used('_option_ok')
|
||||
walker.mark_by_sym_name('_option')
|
||||
}
|
||||
if walker.used_result > 0 {
|
||||
walker.mark_fn_as_used('_result_ok')
|
||||
walker.mark_by_sym_name('_result')
|
||||
}
|
||||
if (walker.used_option + walker.used_result + walker.used_none) > 0 {
|
||||
walker.mark_const_as_used('none__')
|
||||
}
|
||||
walker.mark_by_sym_name('array')
|
||||
|
||||
if table.used_features.asserts {
|
||||
walker.mark_by_sym_name('VAssertMetaInfo')
|
||||
}
|
||||
|
||||
if trace_skip_unused_fn_names {
|
||||
for key, _ in walker.used_fns {
|
||||
@ -538,14 +558,20 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
|
||||
if walker.used_none == 0 {
|
||||
walker.used_fns.delete('${int(ast.none_type)}.str')
|
||||
}
|
||||
|
||||
walker.remove_unused_fn_generic_types()
|
||||
walker.remove_unused_dump_type()
|
||||
|
||||
table.used_features.used_fns = walker.used_fns.move()
|
||||
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()
|
||||
|
||||
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}')
|
||||
}
|
||||
if trace_skip_unused_just_unused_fns {
|
||||
@ -560,7 +586,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) {
|
||||
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) {
|
||||
util.timing_start(@METHOD)
|
||||
defer {
|
||||
util.timing_measure(@METHOD)
|
||||
@ -569,6 +595,7 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast
|
||||
mut all_consts := map[string]ast.ConstField{}
|
||||
mut all_globals := map[string]ast.GlobalField{}
|
||||
mut all_fields := map[string]ast.StructField{}
|
||||
mut all_decltypes := map[string]ast.Type{}
|
||||
for i in 0 .. ast_files.len {
|
||||
for node in ast_files[i].stmts {
|
||||
match node {
|
||||
@ -596,11 +623,14 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast
|
||||
all_fields[sfkey] = sfield
|
||||
}
|
||||
}
|
||||
ast.TypeDecl {
|
||||
all_decltypes[node.name] = node.typ
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return all_fns, all_consts, all_globals, all_fields
|
||||
return all_fns, all_consts, all_globals, all_fields, all_decltypes
|
||||
}
|
||||
|
||||
fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) {
|
||||
|
@ -14,9 +14,8 @@ pub mut:
|
||||
used_fns map[string]bool // used_fns['println'] == true
|
||||
used_consts map[string]bool // used_consts['os.args'] == true
|
||||
used_globals map[string]bool
|
||||
used_structs map[string]bool
|
||||
used_fields map[string]bool
|
||||
used_ifaces map[string]bool
|
||||
used_syms map[int]bool
|
||||
used_none int // _option_none
|
||||
used_option int // _option_ok
|
||||
used_result int // _result_ok
|
||||
@ -25,11 +24,12 @@ pub mut:
|
||||
n_asserts int
|
||||
pref &pref.Preferences = unsafe { nil }
|
||||
mut:
|
||||
files []&ast.File
|
||||
all_fns map[string]ast.FnDecl
|
||||
all_consts map[string]ast.ConstField
|
||||
all_globals map[string]ast.GlobalField
|
||||
all_fields map[string]ast.StructField
|
||||
files []&ast.File
|
||||
all_fns map[string]ast.FnDecl
|
||||
all_consts map[string]ast.ConstField
|
||||
all_globals map[string]ast.GlobalField
|
||||
all_fields map[string]ast.StructField
|
||||
all_decltypes map[string]ast.Type
|
||||
}
|
||||
|
||||
pub fn Walker.new(params Walker) &Walker {
|
||||
@ -78,6 +78,7 @@ pub fn (mut w Walker) mark_const_as_used(ckey string) {
|
||||
w.used_consts[ckey] = true
|
||||
cfield := w.all_consts[ckey] or { return }
|
||||
w.expr(cfield.expr)
|
||||
w.mark_by_type(cfield.typ)
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_global_as_used(ckey string) {
|
||||
@ -91,10 +92,7 @@ pub fn (mut w Walker) mark_global_as_used(ckey string) {
|
||||
gfield := w.all_globals[ckey] or { return }
|
||||
w.expr(gfield.expr)
|
||||
if !gfield.has_expr && gfield.typ != 0 {
|
||||
sym := w.table.sym(gfield.typ)
|
||||
if sym.info is ast.Struct {
|
||||
w.a_struct_info(sym.name, sym.info)
|
||||
}
|
||||
w.mark_by_type(gfield.typ)
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,6 +165,20 @@ pub fn (mut w Walker) mark_markused_globals() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_markused_syms() {
|
||||
for sym in w.table.type_symbols {
|
||||
if sym.info is ast.Struct && sym.info.is_markused {
|
||||
w.mark_by_sym(sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_markused_decltypes() {
|
||||
for _, typ in w.all_decltypes {
|
||||
w.mark_by_type(typ)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_struct_field_default_expr() {
|
||||
for sfkey, mut structfield in w.all_fields {
|
||||
if structfield.has_default_expr {
|
||||
@ -201,7 +213,28 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) {
|
||||
w.stmts(node.stmts)
|
||||
}
|
||||
ast.ComptimeFor {
|
||||
w.mark_by_type(node.typ)
|
||||
w.stmts(node.stmts)
|
||||
match node.kind {
|
||||
.attributes {
|
||||
w.mark_by_sym_name('VAttribute')
|
||||
}
|
||||
.variants {
|
||||
w.mark_by_sym_name('VariantData')
|
||||
}
|
||||
.params {
|
||||
w.mark_by_sym_name('MethodParam')
|
||||
}
|
||||
.values {
|
||||
w.mark_by_sym_name('EnumData')
|
||||
}
|
||||
.fields {
|
||||
w.mark_by_sym_name('FieldData')
|
||||
}
|
||||
.methods {
|
||||
w.mark_by_sym_name('FunctionData')
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.ConstDecl {
|
||||
w.const_fields(node.fields)
|
||||
@ -258,6 +291,9 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) {
|
||||
w.expr(node.db_expr)
|
||||
w.expr(node.or_expr)
|
||||
for line in node.lines {
|
||||
if line.table_expr.typ != 0 {
|
||||
w.mark_by_sym(w.table.sym(line.table_expr.typ))
|
||||
}
|
||||
w.expr(line.where_expr)
|
||||
w.exprs(line.update_exprs)
|
||||
}
|
||||
@ -325,10 +361,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
w.fn_decl(mut node.decl)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
sym := w.table.final_sym(node.elem_type)
|
||||
if sym.info is ast.Struct {
|
||||
w.a_struct_info(sym.name, sym.info)
|
||||
}
|
||||
w.mark_by_type(node.elem_type)
|
||||
w.expr(node.len_expr)
|
||||
w.expr(node.cap_expr)
|
||||
w.expr(node.init_expr)
|
||||
@ -343,19 +376,27 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
}
|
||||
ast.CallExpr {
|
||||
w.call_expr(mut node)
|
||||
if node.name == 'json.decode' {
|
||||
w.mark_by_type((node.args[0].expr as ast.TypeNode).typ)
|
||||
}
|
||||
}
|
||||
ast.CastExpr {
|
||||
w.expr(node.expr)
|
||||
w.expr(node.arg)
|
||||
w.mark_by_type(node.typ)
|
||||
if node.typ.has_flag(.option) {
|
||||
w.used_option++
|
||||
} else if node.typ.has_flag(.result) {
|
||||
w.used_result++
|
||||
}
|
||||
}
|
||||
ast.ChanInit {
|
||||
w.expr(node.cap_expr)
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
ast.ConcatExpr {
|
||||
w.exprs(node.vals)
|
||||
w.mark_by_sym(w.table.sym(node.return_type))
|
||||
}
|
||||
ast.ComptimeSelector {
|
||||
w.expr(node.left)
|
||||
@ -374,6 +415,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
w.expr(node.expr)
|
||||
w.fn_by_name('eprint')
|
||||
w.fn_by_name('eprintln')
|
||||
if node.expr_type != 0 {
|
||||
w.mark_by_type(node.expr_type)
|
||||
}
|
||||
}
|
||||
ast.SpawnExpr {
|
||||
if node.is_expr {
|
||||
@ -403,58 +447,71 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
return
|
||||
}
|
||||
sym := w.table.final_sym(node.left_type)
|
||||
if sym.kind == .map {
|
||||
if sym.info is ast.Map {
|
||||
if node.is_setter {
|
||||
w.mark_builtin_map_method_as_used('set')
|
||||
} else {
|
||||
w.mark_builtin_map_method_as_used('get')
|
||||
}
|
||||
|
||||
w.mark_by_sym(w.table.sym(sym.info.key_type))
|
||||
w.mark_by_sym(w.table.sym(sym.info.value_type))
|
||||
w.features.used_maps++
|
||||
} else if sym.kind == .array {
|
||||
} else if sym.info is ast.Array {
|
||||
if node.is_setter {
|
||||
w.mark_builtin_array_method_as_used('set')
|
||||
} else {
|
||||
w.mark_builtin_array_method_as_used('get')
|
||||
}
|
||||
|
||||
w.mark_by_sym(w.table.sym(sym.info.elem_type))
|
||||
w.features.used_arrays++
|
||||
} else if sym.kind == .string {
|
||||
if node.index is ast.RangeExpr {
|
||||
w.mark_builtin_array_method_as_used('slice')
|
||||
w.features.range_index = true
|
||||
}
|
||||
} else if sym.info is ast.Struct {
|
||||
w.mark_by_sym(sym)
|
||||
} else if sym.info is ast.SumType {
|
||||
w.mark_by_sym(sym)
|
||||
}
|
||||
}
|
||||
ast.InfixExpr {
|
||||
w.expr(node.left)
|
||||
w.expr(node.right)
|
||||
w.or_block(node.or_block)
|
||||
if node.left_type == 0 {
|
||||
return
|
||||
}
|
||||
sym := w.table.sym(node.left_type)
|
||||
if sym.kind == .struct {
|
||||
if opmethod := sym.find_method(node.op.str()) {
|
||||
unsafe {
|
||||
w.fn_decl(mut &ast.FnDecl(opmethod.source_fn))
|
||||
if node.left_type != 0 {
|
||||
sym := w.table.sym(node.left_type)
|
||||
if sym.kind == .struct {
|
||||
if opmethod := sym.find_method(node.op.str()) {
|
||||
unsafe {
|
||||
w.fn_decl(mut &ast.FnDecl(opmethod.source_fn))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.right_type == 0 {
|
||||
return
|
||||
right_type := if node.right_type == 0 && mut node.right is ast.TypeNode {
|
||||
node.right.typ
|
||||
} else {
|
||||
node.right_type
|
||||
}
|
||||
right_sym := w.table.sym(node.right_type)
|
||||
if node.op in [.not_in, .key_in] {
|
||||
if right_sym.kind == .map {
|
||||
w.features.used_maps++
|
||||
} else if right_sym.kind == .array {
|
||||
w.features.used_arrays++
|
||||
if right_type != 0 {
|
||||
right_sym := w.table.sym(right_type)
|
||||
if node.op in [.not_in, .key_in] {
|
||||
if right_sym.kind == .map {
|
||||
w.features.used_maps++
|
||||
} else if right_sym.kind == .array {
|
||||
w.features.used_arrays++
|
||||
}
|
||||
} else if node.op in [.key_is, .not_is] {
|
||||
w.mark_by_sym(right_sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.IfGuardExpr {
|
||||
w.expr(node.expr)
|
||||
if node.expr_type != 0 {
|
||||
w.mark_by_type(node.expr_type)
|
||||
}
|
||||
}
|
||||
ast.IfExpr {
|
||||
w.expr(node.left)
|
||||
@ -470,13 +527,23 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
}
|
||||
.function {
|
||||
w.fn_by_name(node.name)
|
||||
if node.info is ast.IdentFn {
|
||||
w.mark_by_type(node.info.typ)
|
||||
}
|
||||
}
|
||||
.global {
|
||||
w.mark_global_as_used(node.name)
|
||||
}
|
||||
else {
|
||||
// `.unresolved`, `.blank_ident`, `.variable`, `.function`
|
||||
// println('>>> else, ast.Ident kind: $node.kind')
|
||||
// println('>>> else, ast.Ident ${node.name} kind: $node.kind ')
|
||||
if node.name in w.all_consts {
|
||||
w.mark_const_as_used(node.name)
|
||||
} else if node.name in w.all_globals {
|
||||
w.mark_global_as_used(node.name)
|
||||
} else {
|
||||
w.fn_by_name(node.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
w.or_block(node.or_expr)
|
||||
@ -493,12 +560,27 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
if node.has_update_expr {
|
||||
w.expr(node.update_expr)
|
||||
}
|
||||
mapinfo := w.table.final_sym(node.typ).map_info()
|
||||
ksym := w.table.sym(mapinfo.key_type)
|
||||
vsym := w.table.sym(mapinfo.value_type)
|
||||
if node.typ.has_flag(.shared_f) {
|
||||
if sym := w.table.find_sym('sync.RwMutex') {
|
||||
w.mark_by_sym(sym)
|
||||
}
|
||||
}
|
||||
w.mark_by_sym(ksym)
|
||||
w.mark_by_sym(vsym)
|
||||
w.features.used_maps++
|
||||
}
|
||||
ast.MatchExpr {
|
||||
w.expr(node.cond)
|
||||
for b in node.branches {
|
||||
w.exprs(b.exprs)
|
||||
for expr in b.exprs {
|
||||
if expr is ast.TypeNode {
|
||||
w.mark_by_sym(w.table.sym(expr.typ))
|
||||
}
|
||||
}
|
||||
w.stmts(b.stmts)
|
||||
}
|
||||
}
|
||||
@ -525,6 +607,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
}
|
||||
ast.SizeOf, ast.IsRefType {
|
||||
w.expr(node.expr)
|
||||
if node.typ != 0 {
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
w.used_interp++
|
||||
@ -533,14 +618,14 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
ast.SelectorExpr {
|
||||
w.expr(node.expr)
|
||||
if node.expr_type != 0 {
|
||||
esym := w.table.sym(node.expr_type)
|
||||
if esym.kind == .interface {
|
||||
w.mark_interface_by_symbol(esym)
|
||||
}
|
||||
w.mark_by_type(node.expr_type)
|
||||
if method := w.table.find_method(w.table.sym(node.expr_type), node.field_name) {
|
||||
w.fn_by_name(method.fkey())
|
||||
}
|
||||
}
|
||||
if node.typ != 0 {
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
w.or_block(node.or_block)
|
||||
}
|
||||
ast.SqlExpr {
|
||||
@ -550,15 +635,14 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
w.expr(node.order_expr)
|
||||
w.expr(node.limit_expr)
|
||||
w.expr(node.where_expr)
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
ast.StructInit {
|
||||
if node.typ == 0 {
|
||||
return
|
||||
}
|
||||
sym := w.table.sym(node.typ)
|
||||
if sym.info is ast.Struct {
|
||||
w.a_struct_info(sym.name, sym.info)
|
||||
}
|
||||
w.mark_by_sym(sym)
|
||||
if node.has_update_expr {
|
||||
w.expr(node.update_expr)
|
||||
}
|
||||
@ -568,12 +652,16 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
}
|
||||
ast.TypeOf {
|
||||
w.expr(node.expr)
|
||||
if node.typ != 0 {
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
}
|
||||
///
|
||||
ast.AsCast {
|
||||
w.expr(node.expr)
|
||||
w.fn_by_name('__as_cast')
|
||||
w.fn_by_name('new_array_from_c_array')
|
||||
w.mark_by_sym_name('VCastTypeIndexName')
|
||||
}
|
||||
ast.AtExpr {}
|
||||
ast.BoolLiteral {}
|
||||
@ -592,8 +680,12 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
w.expr(filtered[0].expr)
|
||||
}
|
||||
}
|
||||
w.mark_by_sym_name(node.enum_name)
|
||||
}
|
||||
ast.LockExpr {
|
||||
if sym := w.table.find_sym('sync.RwMutex') {
|
||||
w.mark_by_sym(sym)
|
||||
}
|
||||
w.stmts(node.stmts)
|
||||
}
|
||||
ast.OffsetOf {}
|
||||
@ -606,7 +698,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
w.stmts(branch.stmts)
|
||||
}
|
||||
}
|
||||
ast.TypeNode {}
|
||||
ast.TypeNode {
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
ast.UnsafeExpr {
|
||||
w.expr(node.expr)
|
||||
}
|
||||
@ -614,65 +708,13 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) a_struct_info(sname string, info ast.Struct) {
|
||||
if sname in w.used_structs {
|
||||
return
|
||||
}
|
||||
w.used_structs[sname] = true
|
||||
for ifield in info.fields {
|
||||
if ifield.has_default_expr {
|
||||
w.expr(ifield.default_expr)
|
||||
}
|
||||
if ifield.typ != 0 {
|
||||
fsym := w.table.sym(ifield.typ)
|
||||
if ifield.typ.has_flag(.option) {
|
||||
w.used_option++
|
||||
if !ifield.has_default_expr {
|
||||
w.used_none++
|
||||
}
|
||||
}
|
||||
match fsym.info {
|
||||
ast.Struct {
|
||||
w.a_struct_info(fsym.name, fsym.info)
|
||||
}
|
||||
ast.Alias {
|
||||
value_sym := w.table.final_sym(ifield.typ)
|
||||
if value_sym.info is ast.Struct {
|
||||
w.a_struct_info(value_sym.name, value_sym.info)
|
||||
}
|
||||
}
|
||||
ast.Array, ast.ArrayFixed {
|
||||
w.features.used_arrays++
|
||||
value_sym := w.table.final_sym(w.table.value_type(ifield.typ))
|
||||
if value_sym.info is ast.Struct {
|
||||
w.a_struct_info(value_sym.name, value_sym.info)
|
||||
}
|
||||
}
|
||||
ast.Map {
|
||||
w.features.used_maps++
|
||||
value_sym := w.table.final_sym(w.table.value_type(ifield.typ))
|
||||
if value_sym.info is ast.Struct {
|
||||
w.a_struct_info(value_sym.name, value_sym.info)
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
for embed in info.embeds {
|
||||
sym := w.table.final_sym(embed)
|
||||
if sym.info is ast.Struct {
|
||||
w.a_struct_info(sym.name, sym.info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||
if node == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
if node.language == .c {
|
||||
w.mark_fn_as_used(node.fkey())
|
||||
w.mark_fn_ret_and_params(node.return_type, node.params)
|
||||
return
|
||||
}
|
||||
fkey := node.fkey()
|
||||
@ -682,11 +724,10 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||
if node.no_body {
|
||||
return
|
||||
}
|
||||
if node.return_type.has_flag(.option) {
|
||||
w.used_option++
|
||||
} else if node.return_type.has_flag(.result) {
|
||||
w.used_result++
|
||||
if node.is_method {
|
||||
w.mark_by_type(node.receiver.typ)
|
||||
}
|
||||
w.mark_fn_ret_and_params(node.return_type, node.params)
|
||||
w.mark_fn_as_used(fkey)
|
||||
w.stmts(node.stmts)
|
||||
w.defer_stmts(node.defer_stmts)
|
||||
@ -699,13 +740,20 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||
for arg in node.args {
|
||||
w.expr(arg.expr)
|
||||
}
|
||||
for concrete_type in node.concrete_types {
|
||||
w.mark_by_type(concrete_type)
|
||||
}
|
||||
if node.language == .c {
|
||||
if node.name in ['C.wyhash', 'C.wyhash64'] {
|
||||
w.features.used_maps++
|
||||
}
|
||||
if node.return_type != 0 {
|
||||
w.mark_by_type(node.return_type)
|
||||
}
|
||||
return
|
||||
}
|
||||
if node.is_method && node.left_type != 0 {
|
||||
w.mark_by_type(node.left_type)
|
||||
left_sym := w.table.sym(node.left_type)
|
||||
if left_sym.info is ast.Aggregate {
|
||||
for receiver_type in left_sym.info.types {
|
||||
@ -718,7 +766,6 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||
}
|
||||
}
|
||||
} else if left_sym.info is ast.Interface {
|
||||
w.mark_interface_by_symbol(left_sym)
|
||||
for typ in left_sym.info.types {
|
||||
sym := w.table.sym(typ)
|
||||
_, embed_types := w.table.find_method_from_embeds(sym, node.name) or {
|
||||
@ -779,6 +826,7 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||
stmt := w.all_fns[fn_name] or { return }
|
||||
if !stmt.should_be_skipped && stmt.name == node.name {
|
||||
if !node.is_method || receiver_typ == stmt.receiver.typ {
|
||||
w.mark_fn_ret_and_params(stmt.return_type, stmt.params)
|
||||
w.stmts(stmt.stmts)
|
||||
}
|
||||
if node.return_type.has_flag(.option) {
|
||||
@ -795,6 +843,7 @@ pub fn (mut w Walker) fn_by_name(fn_name string) {
|
||||
}
|
||||
stmt := w.all_fns[fn_name] or { return }
|
||||
w.mark_fn_as_used(fn_name)
|
||||
w.mark_fn_ret_and_params(stmt.return_type, stmt.params)
|
||||
w.stmts(stmt.stmts)
|
||||
}
|
||||
|
||||
@ -841,19 +890,174 @@ pub fn (mut w Walker) mark_panic_deps() {
|
||||
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_interface_by_symbol(isym ast.TypeSymbol) {
|
||||
if isym.name in w.used_ifaces {
|
||||
pub fn (mut w Walker) mark_fn_ret_and_params(return_type ast.Type, params []ast.Param) {
|
||||
if return_type != 0 {
|
||||
if return_type.has_flag(.option) {
|
||||
w.used_option++
|
||||
} else if return_type.has_flag(.result) {
|
||||
w.used_result++
|
||||
}
|
||||
w.mark_by_type(return_type.clear_option_and_result())
|
||||
}
|
||||
for param in params {
|
||||
w.mark_by_type(param.typ)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_by_sym_name(name string) {
|
||||
if sym := w.table.find_sym(name) {
|
||||
w.mark_by_sym(sym)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_by_type(typ ast.Type) {
|
||||
if typ.has_flag(.generic) {
|
||||
return
|
||||
}
|
||||
w.used_ifaces[isym.name] = true
|
||||
if isym.info is ast.Interface {
|
||||
for typ in isym.info.types {
|
||||
if typ == ast.map_type {
|
||||
w.features.used_maps++
|
||||
sym := w.table.sym(typ)
|
||||
w.mark_by_sym(sym)
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
|
||||
if isym.idx in w.used_syms {
|
||||
return
|
||||
}
|
||||
w.used_syms[isym.idx] = true
|
||||
match isym.info {
|
||||
ast.Struct {
|
||||
for ifield in isym.info.fields {
|
||||
if ifield.has_default_expr {
|
||||
w.expr(ifield.default_expr)
|
||||
}
|
||||
if ifield.typ != 0 {
|
||||
fsym := w.table.sym(ifield.typ)
|
||||
if ifield.typ.has_flag(.option) {
|
||||
w.used_option++
|
||||
if !ifield.has_default_expr {
|
||||
w.used_none++
|
||||
}
|
||||
}
|
||||
match fsym.info {
|
||||
ast.Struct, ast.SumType, ast.FnType, ast.Alias, ast.Chan {
|
||||
w.mark_by_sym(fsym)
|
||||
}
|
||||
ast.Array, ast.ArrayFixed {
|
||||
w.features.used_arrays++
|
||||
w.mark_by_type(ifield.typ)
|
||||
}
|
||||
ast.Map {
|
||||
w.features.used_maps++
|
||||
w.mark_by_type(ifield.typ)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
for embed in isym.info.embeds {
|
||||
w.mark_by_type(embed)
|
||||
}
|
||||
}
|
||||
ast.ArrayFixed, ast.Array {
|
||||
w.mark_by_type(isym.info.elem_type)
|
||||
}
|
||||
ast.SumType {
|
||||
for typ in isym.info.variants {
|
||||
if typ == ast.map_type {
|
||||
w.features.used_maps++
|
||||
continue
|
||||
}
|
||||
w.mark_by_type(typ)
|
||||
}
|
||||
}
|
||||
ast.Map {
|
||||
w.mark_by_type(isym.info.key_type)
|
||||
w.mark_by_type(isym.info.value_type)
|
||||
w.features.used_maps++
|
||||
}
|
||||
ast.Alias {
|
||||
w.mark_by_type(isym.info.parent_type)
|
||||
}
|
||||
ast.FnType {
|
||||
for param in isym.info.func.params {
|
||||
w.mark_by_type(param.typ)
|
||||
}
|
||||
if isym.info.func.return_type != 0 {
|
||||
w.mark_by_type(isym.info.func.return_type.clear_option_and_result())
|
||||
}
|
||||
}
|
||||
ast.MultiReturn {
|
||||
for typ in isym.info.types {
|
||||
w.mark_by_type(typ)
|
||||
}
|
||||
}
|
||||
ast.Chan {
|
||||
w.mark_by_type(isym.info.elem_type)
|
||||
}
|
||||
ast.Aggregate {
|
||||
for typ in isym.info.types {
|
||||
w.mark_by_type(typ)
|
||||
}
|
||||
}
|
||||
ast.Enum {
|
||||
w.mark_by_type(isym.info.typ)
|
||||
}
|
||||
ast.Interface {
|
||||
for typ in isym.info.types {
|
||||
if typ == ast.map_type {
|
||||
w.features.used_maps++
|
||||
}
|
||||
w.mark_by_type(typ)
|
||||
}
|
||||
for embed in isym.info.embeds {
|
||||
w.mark_by_type(embed)
|
||||
}
|
||||
for generic_type in isym.info.generic_types {
|
||||
w.mark_by_type(generic_type)
|
||||
}
|
||||
if isym.info.parent_type != 0 {
|
||||
w.mark_by_type(isym.info.parent_type)
|
||||
}
|
||||
for method in isym.methods {
|
||||
if method.receiver_type != 0 {
|
||||
w.mark_by_type(method.receiver_type)
|
||||
}
|
||||
w.mark_fn_ret_and_params(method.return_type, method.params)
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) remove_unused_fn_generic_types() {
|
||||
for _, node in w.all_fns {
|
||||
mut count := 0
|
||||
nkey := node.fkey()
|
||||
if all_concrete_types := w.table.fn_generic_types[nkey] {
|
||||
if all_concrete_types.len == 0 {
|
||||
continue
|
||||
}
|
||||
for k, concrete_types in all_concrete_types {
|
||||
if concrete_types.len != 1 {
|
||||
continue
|
||||
}
|
||||
if concrete_types[0].idx() !in w.used_syms {
|
||||
w.table.fn_generic_types[nkey].delete(k - count)
|
||||
count++
|
||||
}
|
||||
}
|
||||
// sym := w.table.sym(typ); eprintln('>>>>>>>>> typ: ${typ.str():-30} | sym.name: ${sym.name}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) remove_unused_dump_type() {
|
||||
for typ, _ in w.table.dumps {
|
||||
if ast.Type(u32(typ)).idx() !in w.used_syms {
|
||||
w.table.dumps.delete(typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2605,6 +2605,7 @@ fn source_name(name string) string {
|
||||
}
|
||||
|
||||
fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
attrs := p.attrs
|
||||
start_pos := p.tok.pos()
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
@ -2648,7 +2649,6 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
p.table.sym(fn_type).is_pub = is_pub
|
||||
type_pos = type_pos.extend(p.tok.pos())
|
||||
comments = p.eat_comments(same_line: true)
|
||||
attrs := p.attrs
|
||||
p.attrs = []
|
||||
return ast.FnTypeDecl{
|
||||
name: fn_name
|
||||
@ -2659,6 +2659,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
comments: comments
|
||||
generic_types: generic_types
|
||||
attrs: attrs
|
||||
is_markused: attrs.contains('markused')
|
||||
}
|
||||
}
|
||||
sum_variants << p.parse_sum_type_variants()
|
||||
@ -2704,6 +2705,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
attrs: p.attrs
|
||||
pos: decl_pos
|
||||
name_pos: name_pos
|
||||
is_markused: attrs.contains('markused')
|
||||
}
|
||||
p.table.register_sumtype(node)
|
||||
return node
|
||||
@ -2755,6 +2757,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
type_pos: type_pos.extend(type_end_pos)
|
||||
pos: decl_pos
|
||||
comments: comments
|
||||
is_markused: attrs.contains('markused')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,6 +406,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
|
||||
is_typedef: attrs.contains('typedef')
|
||||
is_union: is_union
|
||||
is_heap: attrs.contains('heap')
|
||||
is_markused: attrs.contains('markused')
|
||||
is_minify: is_minify
|
||||
is_generic: generic_types.len > 0
|
||||
generic_types: generic_types
|
||||
|
1
vlib/v/tests/skip_unused/skip_sumtype_unused.run.out
Normal file
1
vlib/v/tests/skip_unused/skip_sumtype_unused.run.out
Normal file
@ -0,0 +1 @@
|
||||
256
|
@ -0,0 +1 @@
|
||||
256
|
6
vlib/v/tests/skip_unused/skip_sumtype_unused.vv
Normal file
6
vlib/v/tests/skip_unused/skip_sumtype_unused.vv
Normal file
@ -0,0 +1,6 @@
|
||||
import encoding.binary
|
||||
|
||||
fn main() {
|
||||
x := binary.big_endian_u16_fixed([u8(1), 0]!)
|
||||
println(x)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user