autofree: handle early returns (part 1)

pull/6815/head
Alexander Medvednikov 2020-11-16 17:26:54 +01:00
parent fdfe2a4e68
commit 68077b7dbf
2 changed files with 19 additions and 8 deletions

View File

@ -766,12 +766,15 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) {
// use the first stmt to get the scope
stmt := stmts[0]
// stmt := stmts[stmts.len-1]
if stmt !is ast.FnDecl {
if stmt !is ast.FnDecl && g.inside_ternary == 0 {
// g.writeln('// autofree scope')
// g.writeln('// autofree_scope_vars($stmt.position().pos) | ${typeof(stmt)}')
// go back 1 position is important so we dont get the
// internal scope of for loops and possibly other nodes
g.autofree_scope_vars(stmt.position().pos - 1)
// g.autofree_scope_vars(stmt.position().pos - 1)
stmt_pos := stmt.position()
g.writeln('// af scope_vars')
g.autofree_scope_vars(stmt_pos.pos - 1, stmt_pos.line_nr)
}
}
}
@ -2022,7 +2025,7 @@ fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad
return true
}
fn (mut g Gen) autofree_scope_vars(pos int) {
fn (mut g Gen) autofree_scope_vars(pos int, line_nr int) {
if g.is_builtin_mod {
// In `builtin` everything is freed manually.
return
@ -2030,10 +2033,12 @@ fn (mut g Gen) autofree_scope_vars(pos int) {
// eprintln('> free_scope_vars($pos)')
scope := g.file.scope.innermost(pos)
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.end_pos)
g.autofree_scope_vars2(scope, scope.start_pos, scope.end_pos, line_nr)
}
fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, end_pos int) {
// fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, end_pos int) {
fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int, line_nr int) {
if isnil(scope) {
return
}
@ -2046,7 +2051,8 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, end_pos int) {
// continue
// }
v := *obj
if v.pos.pos > end_pos {
// if v.pos.pos > end_pos {
if v.pos.pos > end_pos || (v.pos.pos < start_pos && v.pos.line_nr == line_nr) {
// Do not free vars that were declared after this scope
continue
}
@ -2068,8 +2074,11 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, end_pos int) {
// return
// }
// ```
// if !isnil(scope.parent) && line_nr > 0 {
if !isnil(scope.parent) {
// g.autofree_scope_vars2(scope.parent, end_pos)
g.writeln('// af parent scope:')
// g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr)
}
}
@ -3415,6 +3424,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
g.writeln('$styp $tmp; /* if prepend */')
} else if node.is_expr || g.inside_ternary != 0 {
g.inside_ternary++
// g.inside_if_expr = true
g.write('(')
for i, branch in node.branches {
if i > 0 {
@ -3952,7 +3962,7 @@ fn (mut g Gen) return_statement(node ast.Return, af bool) {
}
if free {
g.writeln('; // free tmp exprs')
g.autofree_scope_vars(node.pos.pos + 1)
g.autofree_scope_vars(node.pos.pos + 1, node.pos.line_nr)
g.write('return $tmp')
}
} else {

View File

@ -155,7 +155,8 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
//
if g.autofree && !g.pref.experimental {
// TODO: remove this, when g.write_autofree_stmts_when_needed works properly
g.autofree_scope_vars(it.body_pos.pos)
g.writeln('// af scope_vars (fn decl)')
g.autofree_scope_vars(it.body_pos.pos, it.body_pos.line_nr)
}
if it.return_type != table.void_type && it.stmts.len > 0 && it.stmts.last() !is ast.Return {
default_expr := g.type_default(it.return_type)