autofree: fix `or {}`; ci: bring back gitly -autofree

pull/7119/head
Alexander Medvednikov 2020-12-04 18:06:53 +01:00
parent 3f2133c65e
commit 0ea2fa228f
5 changed files with 29 additions and 16 deletions

View File

@ -170,7 +170,7 @@ jobs:
run: ./v -silent build-examples
- name: Build examples with -autofree
run: |
./v -autofree -experimental -o tetris examples/tetris/tetris.v
./v -autofree -o tetris examples/tetris/tetris.v
- name: v doctor
run: |
./v doctor
@ -182,7 +182,7 @@ jobs:
run: |
git clone --depth 1 https://github.com/vlang/ved
cd ved && ../v -o ved .
# ../v -autofree .
../v -autofree .
- name: Build V UI examples
run: |
git clone --depth 1 https://github.com/vlang/ui
@ -538,6 +538,7 @@ jobs:
git clone --depth 1 https://github.com/vlang/gitly
cd gitly
../v .
../v -autofree .
cd ..
websocket_autobahn:

View File

@ -311,9 +311,6 @@ pub mut:
generic_type table.Type // TODO array, to support multiple types
generic_list_pos token.Position
free_receiver bool // true if the receiver expression needs to be freed
// autofree_pregen string
// autofree_vars []AutofreeArgVar
// autofree_vars_ids []int
}
/*
@ -371,6 +368,8 @@ pub mut:
pos token.Position
is_used bool
is_changed bool // to detect mutable vars that are never changed
is_or bool // `x := foo() or { ... }`
// (for setting the position after the or block for autofree)
}
// used for smartcasting only

View File

@ -1079,7 +1079,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
}
ast.Module {
// g.is_builtin_mod = node.name == 'builtin'
g.is_builtin_mod = node.name in ['builtin', 'os', 'strconv', 'strings']
g.is_builtin_mod = node.name in ['builtin', 'os', 'strconv', 'strings', 'gg']
g.cur_mod = node.name
}
ast.Return {
@ -2070,7 +2070,7 @@ fn (mut g Gen) autofree_scope_vars(pos int, line_nr int, free_parent_scopes bool
// 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.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)
}
@ -2083,11 +2083,16 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int
for _, obj in scope.objects {
match obj {
ast.Var {
g.writeln('// var $obj.name pos=$obj.pos.pos')
g.writeln('// var "$obj.name" var.pos=$obj.pos.pos var.line_nr=$obj.pos.line_nr')
if obj.name == g.returned_var_name {
g.writeln('// skipping returned var')
continue
}
if obj.is_or {
// Skip vars inited with the `or {}`, since they are generated
// after the or block in C.
continue
}
// if var.typ == 0 {
// // TODO why 0?
// continue
@ -2117,7 +2122,6 @@ 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) {
// 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, true)
}
@ -3918,7 +3922,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
} else {
if g.pref.autofree && !g.is_builtin_mod {
g.writeln('// free before return (no values returned)')
g.autofree_scope_vars(node.pos.pos + 1, node.pos.line_nr, true)
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
}
g.writeln('return;')
}

View File

@ -423,7 +423,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} else if !node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name != 'str' {
g.write('/*rec*/*')
}
if node.free_receiver && !g.inside_lambda {
if node.free_receiver && !g.inside_lambda && !g.is_builtin_mod {
// The receiver expression needs to be freed, use the temp var.
fn_name := node.name.replace('.', '_')
arg_name := '_arg_expr_${fn_name}_0_$node.pos.pos'
@ -652,7 +652,7 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
} else {
scope.register(ast.Var{
name: t
typ: table.string_type // is_arg: true // TODO hack so that it's not freed twice when out of scope. it's probably better to use one model
typ: table.string_type
is_autofree_tmp: true
})
s = 'string $t = '
@ -662,10 +662,7 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
// g.writeln(';// new af pre')
s += ';// new af2 pre'
g.strs_to_free0 << s
// Now free the tmp arg vars right after the function call
// g.strs_to_free << t
// g.nr_vars_to_free++
// g.strs_to_free << 'string_free(&$t);'
// This tmp arg var will be freed with the rest of the vars at the end of the scope.
}
}

View File

@ -131,6 +131,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
is_static = true
}
}
r0 := right[0]
mut v := ast.Var{
name: lx.name
expr: if left.len == right.len { right[i] } else { ast.Expr{} }
@ -138,6 +139,17 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
is_mut: lx.is_mut || p.inside_for
pos: lx.pos
}
if p.pref.autofree {
if r0 is ast.CallExpr {
// Set correct variable position (after the or block)
// so that autofree doesn't free it in cgen before
// it's declared. (`Or` variables are declared after the or block).
if r0.or_block.pos.pos > 0 {
v.is_or = true
// v.pos = r0.or_block.pos.
}
}
}
obj := ast.ScopeObject(v)
lx.obj = obj
p.scope.register(obj)