cgen: autofree - know where to stop freeing parent scops on continue/break

pull/7216/head
joe-conigliaro 2020-12-06 02:36:27 +11:00
parent fafe30b6aa
commit 83f651c29a
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
5 changed files with 34 additions and 15 deletions

View File

@ -286,9 +286,10 @@ pub mut:
// break, continue
pub struct BranchStmt {
pub:
kind token.Kind
label string
pos token.Position
kind token.Kind
label string
pos token.Position
parent_pos int
}
pub struct CallExpr {

View File

@ -858,7 +858,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
// continue or break
if g.pref.autofree && !g.is_builtin_mod {
g.writeln('// free before continue/break')
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, false)
g.autofree_scope_vars_stop(node.pos.pos - 1, node.pos.line_nr, true,
node.parent_pos)
}
g.writeln('$node.kind;')
}
@ -2061,8 +2062,11 @@ 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, line_nr int) {
fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool) {
g.autofree_scope_vars_stop(pos, line_nr, free_parent_scopes, -1)
}
fn (mut g Gen) autofree_scope_vars_stop(pos int, line_nr int, free_parent_scopes bool, stop_pos int) {
if g.is_builtin_mod {
// In `builtin` everything is freed manually.
return
@ -2078,12 +2082,12 @@ fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool
return
}
g.writeln('// autofree_scope_vars(pos=$pos line_nr=$line_nr 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)
g.autofree_scope_vars2(scope, scope.start_pos, scope.end_pos, line_nr, free_parent_scopes,
stop_pos)
}
// 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, free_parent_scopes bool) {
fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int, line_nr int, free_parent_scopes bool, stop_pos int) {
if isnil(scope) {
return
}
@ -2129,9 +2133,10 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int
// }
// ```
// if !isnil(scope.parent) && line_nr > 0 {
if free_parent_scopes && !isnil(scope.parent) {
if free_parent_scopes && !isnil(scope.parent) &&
(stop_pos == -1 || scope.parent.start_pos >= stop_pos) {
g.writeln('// af parent scope:')
g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr, true)
g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr, true, stop_pos)
}
}

View File

@ -9,6 +9,7 @@ import v.table
fn (mut p Parser) for_stmt() ast.Stmt {
p.check(.key_for)
pos := p.tok.position()
p.branch_parent_pos = pos.pos
p.open_scope()
p.inside_for = true
if p.tok.kind == .key_match {

View File

@ -60,6 +60,7 @@ mut:
vet_errors []string
cur_fn_name string
in_generic_params bool // indicates if parsing between `<` and `>` of a method/function
branch_parent_pos int // used in BranchStmt (continue/break) autofree stop position
}
// for tests
@ -690,6 +691,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
kind: tok.kind
label: label
pos: tok.position()
parent_pos: p.branch_parent_pos
}
}
.key_unsafe {

View File

@ -258,17 +258,28 @@ fn free_before_break() {
q := [1, 2, 3]
break
}
/*
for {
qq := [1, 2, 3]
aa := [1, 2, 3]
if true {
// breaking should free only vars in the closest for loop's scope
// `qq`, not `s`
break
}
// nested 1
for {
bb := [4, 5, 6]
if true {
break
}
// nested 2
for {
cc := [7, 8, 9]
if true {
break
}
}
}
}
*/
/*
mut i := 0
for {
i++
@ -280,7 +291,6 @@ fn free_before_break() {
continue
}
}
*/
}
struct User {