autofree: handle method chains
parent
ab137e4164
commit
66b8462d7a
|
@ -288,6 +288,7 @@ pub mut:
|
||||||
return_type table.Type
|
return_type table.Type
|
||||||
should_be_skipped bool
|
should_be_skipped bool
|
||||||
generic_type table.Type // TODO array, to support multiple types
|
generic_type table.Type // TODO array, to support multiple types
|
||||||
|
free_receiver bool // true if the receiver expression needs to be freed
|
||||||
// autofree_pregen string
|
// autofree_pregen string
|
||||||
// autofree_vars []AutofreeArgVar
|
// autofree_vars []AutofreeArgVar
|
||||||
// autofree_vars_ids []int
|
// autofree_vars_ids []int
|
||||||
|
|
|
@ -952,7 +952,7 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type {
|
||||||
*/
|
*/
|
||||||
// Now call `call_method` or `call_fn` for specific checks.
|
// Now call `call_method` or `call_fn` for specific checks.
|
||||||
typ := if call_expr.is_method { c.call_method(mut call_expr) } else { c.call_fn(mut call_expr) }
|
typ := if call_expr.is_method { c.call_method(mut call_expr) } else { c.call_fn(mut call_expr) }
|
||||||
// autofree
|
// 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 &&
|
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)
|
call_expr.args.len > 0 && !call_expr.args[0].typ.has_flag(.optional)
|
||||||
if free_tmp_arg_vars {
|
if free_tmp_arg_vars {
|
||||||
|
@ -965,6 +965,10 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type {
|
||||||
}
|
}
|
||||||
call_expr.args[i].is_tmp_autofree = true
|
call_expr.args[i].is_tmp_autofree = true
|
||||||
}
|
}
|
||||||
|
if call_expr.receiver_type == table.string_type && !(call_expr.left is ast.Ident ||
|
||||||
|
call_expr.left is ast.StringLiteral) {
|
||||||
|
call_expr.free_receiver = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,7 +443,14 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
} else if !node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name != 'str' {
|
} else if !node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name != 'str' {
|
||||||
g.write('/*rec*/*')
|
g.write('/*rec*/*')
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
if node.free_receiver {
|
||||||
|
// The receiver expression needs to be freed, use the temp var.
|
||||||
|
fn_name := node.name.replace('.', '_')
|
||||||
|
arg_name := '_arg_expr_${fn_name}_0'
|
||||||
|
g.write('/*af receiver arg*/' + arg_name)
|
||||||
|
} else {
|
||||||
|
g.expr(node.left)
|
||||||
|
}
|
||||||
is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len -
|
is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len -
|
||||||
1].has_flag(.variadic)
|
1].has_flag(.variadic)
|
||||||
if node.args.len > 0 || is_variadic {
|
if node.args.len > 0 || is_variadic {
|
||||||
|
@ -631,7 +638,15 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
|
||||||
free_tmp_arg_vars = false // set the flag to true only if we have at least one arg to free
|
free_tmp_arg_vars = false // set the flag to true only if we have at least one arg to free
|
||||||
g.tmp_count2++
|
g.tmp_count2++
|
||||||
mut scope := g.file.scope.innermost(node.pos.pos)
|
mut scope := g.file.scope.innermost(node.pos.pos)
|
||||||
for i, arg in node.args {
|
// prepend the receiver for now (TODO turn the receiver into a CallArg everywhere?)
|
||||||
|
mut args := [ast.CallArg{
|
||||||
|
typ: node.receiver_type
|
||||||
|
expr: node.left
|
||||||
|
is_tmp_autofree: node.free_receiver
|
||||||
|
}]
|
||||||
|
args << node.args
|
||||||
|
// for i, arg in node.args {
|
||||||
|
for i, arg in args {
|
||||||
if !arg.is_tmp_autofree {
|
if !arg.is_tmp_autofree {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -725,7 +740,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
// Use these variables here.
|
// Use these variables here.
|
||||||
fn_name := node.name.replace('.', '_')
|
fn_name := node.name.replace('.', '_')
|
||||||
// name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
// name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
||||||
name := '_arg_expr_${fn_name}_$i'
|
name := '_arg_expr_${fn_name}_${i + 1}'
|
||||||
g.write('/*af arg*/' + name)
|
g.write('/*af arg*/' + name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -736,7 +751,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
// TODO copypasta, move to an inline fn
|
// TODO copypasta, move to an inline fn
|
||||||
fn_name := node.name.replace('.', '_')
|
fn_name := node.name.replace('.', '_')
|
||||||
// name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
// name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
||||||
name := '_arg_expr_${fn_name}_$i'
|
name := '_arg_expr_${fn_name}_${i + 1}'
|
||||||
g.write('/*af arg2*/' + name)
|
g.write('/*af arg2*/' + name)
|
||||||
} else {
|
} else {
|
||||||
g.expr(arg.expr)
|
g.expr(arg.expr)
|
||||||
|
|
|
@ -3,7 +3,7 @@ fn return_array(array_arg []string) []int { // array argument must not be freed
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo() {
|
fn simple() {
|
||||||
nums := [1, 2, 3] // local array must be freed
|
nums := [1, 2, 3] // local array must be freed
|
||||||
println(nums)
|
println(nums)
|
||||||
nums_copy := nums // array assignments call .clone()
|
nums_copy := nums // array assignments call .clone()
|
||||||
|
@ -73,6 +73,15 @@ fn str_replace() {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fooo(s string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn str_replace2() {
|
||||||
|
mut s := 'hello world'
|
||||||
|
s = s.replace('hello', 'hi').replace('world', 'planet')
|
||||||
|
println(s)
|
||||||
|
}
|
||||||
|
|
||||||
fn reassign_str() {
|
fn reassign_str() {
|
||||||
mut s := 'a' + 'b'
|
mut s := 'a' + 'b'
|
||||||
s = 'x' + 'y' // 'a' + 'b' must be freed before the re-assignment
|
s = 'x' + 'y' // 'a' + 'b' must be freed before the re-assignment
|
||||||
|
@ -149,7 +158,7 @@ fn tt() {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println('start')
|
println('start')
|
||||||
foo()
|
simple()
|
||||||
str_tmp_expr()
|
str_tmp_expr()
|
||||||
str_tmp_expr_advanced()
|
str_tmp_expr_advanced()
|
||||||
str_tmp_expr_advanced_var_decl()
|
str_tmp_expr_advanced_var_decl()
|
||||||
|
@ -159,6 +168,7 @@ fn main() {
|
||||||
optional_str()
|
optional_str()
|
||||||
optional_return()
|
optional_return()
|
||||||
str_replace()
|
str_replace()
|
||||||
|
str_replace2()
|
||||||
if_cond()
|
if_cond()
|
||||||
addition_with_tmp_expr()
|
addition_with_tmp_expr()
|
||||||
println('end')
|
println('end')
|
||||||
|
|
Loading…
Reference in New Issue