cgen: properly handle initialization expression for globals (#10981)
parent
61ed1d810f
commit
45ad48d76a
|
@ -535,11 +535,11 @@ pub:
|
|||
pub struct GlobalField {
|
||||
pub:
|
||||
name string
|
||||
expr Expr
|
||||
has_expr bool
|
||||
pos token.Position
|
||||
typ_pos token.Position
|
||||
pub mut:
|
||||
expr Expr
|
||||
typ Type
|
||||
comments []Comment
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ pub mut:
|
|||
is_fmt bool
|
||||
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
used_globals map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
used_vweb_types []Type // vweb context types, filled in by checker, when pref.skip_unused = true;
|
||||
used_maps int // how many times maps were used, filled in by checker, when pref.skip_unused = true;
|
||||
panic_handler FnPanicHandler = default_table_panic_handler
|
||||
|
@ -52,6 +53,7 @@ pub fn (t &Table) free() {
|
|||
t.cmod_prefix.free()
|
||||
t.used_fns.free()
|
||||
t.used_consts.free()
|
||||
t.used_globals.free()
|
||||
t.used_vweb_types.free()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4544,7 +4544,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
c.for_stmt(mut node)
|
||||
}
|
||||
ast.GlobalDecl {
|
||||
c.global_decl(node)
|
||||
c.global_decl(mut node)
|
||||
}
|
||||
ast.GotoLabel {}
|
||||
ast.GotoStmt {
|
||||
|
@ -4793,8 +4793,8 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
|||
c.in_for_count--
|
||||
}
|
||||
|
||||
fn (mut c Checker) global_decl(node ast.GlobalDecl) {
|
||||
for field in node.fields {
|
||||
fn (mut c Checker) global_decl(mut node ast.GlobalDecl) {
|
||||
for mut field in node.fields {
|
||||
c.check_valid_snake_case(field.name, 'global name', field.pos)
|
||||
if field.name in c.global_names {
|
||||
c.error('duplicate global `$field.name`', field.pos)
|
||||
|
@ -4803,6 +4803,14 @@ fn (mut c Checker) global_decl(node ast.GlobalDecl) {
|
|||
if sym.kind == .placeholder {
|
||||
c.error('unknown type `$sym.name`', field.typ_pos)
|
||||
}
|
||||
if field.expr !is ast.EmptyExpr {
|
||||
expr_typ := c.expr(field.expr)
|
||||
if !c.check_types(expr_typ, field.typ) {
|
||||
got_sym := c.table.get_type_symbol(expr_typ)
|
||||
c.error('cannot initialize global variable `$field.name` of type `$sym.name` with expression of type `$got_sym.name`',
|
||||
field.expr.position())
|
||||
}
|
||||
}
|
||||
c.global_names << field.name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5113,9 +5113,18 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
|
|||
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
||||
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
|
||||
for field in node.fields {
|
||||
if g.pref.skip_unused {
|
||||
if field.name !in g.table.used_globals {
|
||||
$if trace_skip_unused_globals ? {
|
||||
eprintln('>> skipping unused global name: $field.name')
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
styp := g.typ(field.typ)
|
||||
if field.has_expr {
|
||||
g.definitions.writeln('$mod$styp $field.name = $field.expr; // global')
|
||||
g.definitions.writeln('$mod$styp $field.name;')
|
||||
g.global_initializations.writeln('\t$field.name = ${g.expr_string(field.expr)}; // global')
|
||||
} else {
|
||||
default_initializer := g.type_default(field.typ)
|
||||
if default_initializer == '{0}' {
|
||||
|
|
|
@ -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, pref &pref.Preferences, ast_files []&ast.File) {
|
||||
mut all_fns, all_consts := all_fn_and_const(ast_files)
|
||||
mut all_fns, all_consts, all_globals := all_fn_const_and_global(ast_files)
|
||||
util.timing_start(@METHOD)
|
||||
defer {
|
||||
util.timing_measure(@METHOD)
|
||||
|
@ -316,6 +316,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
|||
files: ast_files
|
||||
all_fns: all_fns
|
||||
all_consts: all_consts
|
||||
all_globals: all_globals
|
||||
pref: pref
|
||||
}
|
||||
// println( all_fns.keys() )
|
||||
|
@ -368,21 +369,24 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
|||
|
||||
table.used_fns = walker.used_fns.move()
|
||||
table.used_consts = walker.used_consts.move()
|
||||
table.used_globals = walker.used_globals.move()
|
||||
|
||||
$if trace_skip_unused ? {
|
||||
eprintln('>> t.used_fns: $table.used_fns.keys()')
|
||||
eprintln('>> t.used_consts: $table.used_consts.keys()')
|
||||
eprintln('>> t.used_globals: $table.used_globals.keys()')
|
||||
eprintln('>> walker.table.used_maps: $walker.table.used_maps')
|
||||
}
|
||||
}
|
||||
|
||||
fn all_fn_and_const(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField) {
|
||||
fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField) {
|
||||
util.timing_start(@METHOD)
|
||||
defer {
|
||||
util.timing_measure(@METHOD)
|
||||
}
|
||||
mut all_fns := map[string]ast.FnDecl{}
|
||||
mut all_consts := map[string]ast.ConstField{}
|
||||
mut all_globals := map[string]ast.GlobalField{}
|
||||
for i in 0 .. ast_files.len {
|
||||
file := ast_files[i]
|
||||
for node in file.stmts {
|
||||
|
@ -397,9 +401,15 @@ fn all_fn_and_const(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]as
|
|||
all_consts[ckey] = cfield
|
||||
}
|
||||
}
|
||||
ast.GlobalDecl {
|
||||
for gfield in node.fields {
|
||||
gkey := gfield.name
|
||||
all_globals[gkey] = gfield
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return all_fns, all_consts
|
||||
return all_fns, all_consts, all_globals
|
||||
}
|
||||
|
|
|
@ -12,12 +12,14 @@ pub mut:
|
|||
table &ast.Table
|
||||
used_fns map[string]bool // used_fns['println'] == true
|
||||
used_consts map[string]bool // used_consts['os.args'] == true
|
||||
used_globals map[string]bool
|
||||
n_asserts int
|
||||
pref &pref.Preferences
|
||||
mut:
|
||||
files []&ast.File
|
||||
all_fns map[string]ast.FnDecl
|
||||
all_consts map[string]ast.ConstField
|
||||
all_globals map[string]ast.GlobalField
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_fn_as_used(fkey string) {
|
||||
|
@ -36,6 +38,15 @@ pub fn (mut w Walker) mark_const_as_used(ckey string) {
|
|||
w.expr(cfield.expr)
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_global_as_used(ckey string) {
|
||||
$if trace_skip_unused_marked ? {
|
||||
eprintln(' global > |$ckey|')
|
||||
}
|
||||
w.used_globals[ckey] = true
|
||||
gfield := w.all_globals[ckey] or { return }
|
||||
w.expr(gfield.expr)
|
||||
}
|
||||
|
||||
pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) {
|
||||
for fn_name in all_fn_root_names {
|
||||
if fn_name !in w.used_fns {
|
||||
|
@ -268,8 +279,11 @@ fn (mut w Walker) expr(node ast.Expr) {
|
|||
.function {
|
||||
w.fn_by_name(node.name)
|
||||
}
|
||||
.global {
|
||||
w.mark_global_as_used(node.name)
|
||||
}
|
||||
else {
|
||||
// `.unresolved`, `.blank_ident`, `.variable`, `.global`, `.function`
|
||||
// `.unresolved`, `.blank_ident`, `.variable`, `.function`
|
||||
// println('>>> else, ast.Ident kind: $node.kind')
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue