autofree: minor fixes; skip in consts

pull/6912/head
Alexander Medvednikov 2020-11-21 19:07:47 +01:00
parent ad940ff40e
commit 2afb9b30e9
4 changed files with 66 additions and 42 deletions

View File

@ -57,7 +57,7 @@ pub fn load_from_memory(buf byteptr, bufsize int) ?Image {
}
pub fn (img Image) free() {
pub fn (img &Image) free() {
C.stbi_image_free(img.data)
}

View File

@ -53,6 +53,7 @@ pub mut:
mod string // current module name
is_builtin_mod bool // are we in `builtin`?
inside_unsafe bool
inside_const bool
skip_flags bool // should `#flag` and `#include` be skipped
cur_generic_type table.Type
mut:
@ -1028,7 +1029,7 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type {
// autofree: mark args that have to be freed (after saving them in tmp exprs)
free_tmp_arg_vars := c.pref.autofree && c.pref.experimental && !c.is_builtin_mod &&
call_expr.args.len > 0 && !call_expr.args[0].typ.has_flag(.optional)
if free_tmp_arg_vars {
if free_tmp_arg_vars && !c.inside_const {
for i, arg in call_expr.args {
if arg.typ != table.string_type {
continue
@ -1896,6 +1897,48 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
}
}
pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
mut field_names := []string{}
mut field_order := []int{}
for i, field in node.fields {
// TODO Check const name once the syntax is decided
if field.name in c.const_names {
c.error('duplicate const `$field.name`', field.pos)
}
c.const_names << field.name
field_names << field.name
field_order << i
}
mut needs_order := false
mut done_fields := []int{}
for i, field in node.fields {
c.const_decl = field.name
c.const_deps << field.name
typ := c.expr(field.expr)
node.fields[i].typ = c.table.mktyp(typ)
for cd in c.const_deps {
for j, f in node.fields {
if j != i && cd in field_names && cd == f.name && j !in done_fields {
needs_order = true
x := field_order[j]
field_order[j] = field_order[i]
field_order[i] = x
break
}
}
}
done_fields << i
c.const_deps = []
}
if needs_order {
mut ordered_fields := []ast.ConstField{}
for order in field_order {
ordered_fields << node.fields[order]
}
node.fields = ordered_fields
}
}
pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
c.check_valid_pascal_case(decl.name, 'enum name', decl.pos)
mut seen := []int{}
@ -2421,45 +2464,9 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.stmts(node.stmts)
}
ast.ConstDecl {
mut field_names := []string{}
mut field_order := []int{}
for i, field in node.fields {
// TODO Check const name once the syntax is decided
if field.name in c.const_names {
c.error('duplicate const `$field.name`', field.pos)
}
c.const_names << field.name
field_names << field.name
field_order << i
}
mut needs_order := false
mut done_fields := []int{}
for i, field in node.fields {
c.const_decl = field.name
c.const_deps << field.name
typ := c.expr(field.expr)
node.fields[i].typ = c.table.mktyp(typ)
for cd in c.const_deps {
for j, f in node.fields {
if j != i && cd in field_names && cd == f.name && j !in done_fields {
needs_order = true
x := field_order[j]
field_order[j] = field_order[i]
field_order[i] = x
break
}
}
}
done_fields << i
c.const_deps = []
}
if needs_order {
mut ordered_fields := []ast.ConstField{}
for order in field_order {
ordered_fields << node.fields[order]
}
node.fields = ordered_fields
}
c.inside_const = true
c.const_decl(mut node)
c.inside_const = false
}
ast.DeferStmt {
c.stmts(node.stmts)

View File

@ -2069,8 +2069,16 @@ fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool
// In `builtin` everything is freed manually.
return
}
if pos == -1 {
// TODO why can pos be -1?
return
}
// eprintln('> free_scope_vars($pos)')
scope := g.file.scope.innermost(pos)
if scope.start_pos == 0 {
// TODO why can scope.pos be 0? (only outside fns?)
return
}
g.writeln('// autofree_scope_vars(pos=$pos scope.pos=$scope.start_pos scope.end_pos=$scope.end_pos)')
// g.autofree_scope_vars2(scope, scope.end_pos)
g.autofree_scope_vars2(scope, scope.start_pos, scope.end_pos, line_nr, free_parent_scopes)
@ -3460,9 +3468,15 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
// For if expressions with multiple statements or another if expression inside, it's much
// easier to use a temp var, than do C tricks with commas, introduce special vars etc
// (as it used to be done).
// Always use this in -autofree, since ?: can have tmp expressions that have to be freed.
needs_tmp_var := node.is_expr &&
(g.pref.autofree || (g.pref.experimental &&
(node.branches[0].stmts.len > 1 || node.branches[0].stmts[0] is ast.IfExpr)))
/*
needs_tmp_var := node.is_expr &&
(g.pref.autofree || g.pref.experimental) &&
(node.branches[0].stmts.len > 1 || node.branches[0].stmts[0] is ast.IfExpr)
*/
tmp := if needs_tmp_var { g.new_tmp_var() } else { '' }
mut cur_line := ''
if needs_tmp_var {

View File

@ -647,6 +647,9 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
if g.is_js_call {
return
}
if g.inside_const {
return
}
free_tmp_arg_vars = false // set the flag to true only if we have at least one arg to free
g.tmp_count2++
mut scope := g.file.scope.innermost(node.pos.pos)
@ -778,7 +781,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
break
}
use_tmp_var_autofree := g.autofree && g.pref.experimental && arg.typ == table.string_type &&
arg.is_tmp_autofree
arg.is_tmp_autofree && !g.inside_const
// g.write('/* af=$arg.is_tmp_autofree */')
mut is_interface := false
// some c fn definitions dont have args (cfns.v) or are not updated in checker