autofree: handle method chains
parent
ab137e4164
commit
66b8462d7a
|
@ -288,6 +288,7 @@ pub mut:
|
|||
return_type table.Type
|
||||
should_be_skipped bool
|
||||
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_vars []AutofreeArgVar
|
||||
// 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.
|
||||
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 &&
|
||||
call_expr.args.len > 0 && !call_expr.args[0].typ.has_flag(.optional)
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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' {
|
||||
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 -
|
||||
1].has_flag(.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
|
||||
g.tmp_count2++
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
|
@ -725,7 +740,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
|||
// Use these variables here.
|
||||
fn_name := node.name.replace('.', '_')
|
||||
// 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)
|
||||
}
|
||||
} else {
|
||||
|
@ -736,7 +751,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
|||
// TODO copypasta, move to an inline fn
|
||||
fn_name := node.name.replace('.', '_')
|
||||
// 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)
|
||||
} else {
|
||||
g.expr(arg.expr)
|
||||
|
|
|
@ -3,7 +3,7 @@ fn return_array(array_arg []string) []int { // array argument must not be freed
|
|||
return s
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
fn simple() {
|
||||
nums := [1, 2, 3] // local array must be freed
|
||||
println(nums)
|
||||
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() {
|
||||
mut s := 'a' + 'b'
|
||||
s = 'x' + 'y' // 'a' + 'b' must be freed before the re-assignment
|
||||
|
@ -149,7 +158,7 @@ fn tt() {
|
|||
|
||||
fn main() {
|
||||
println('start')
|
||||
foo()
|
||||
simple()
|
||||
str_tmp_expr()
|
||||
str_tmp_expr_advanced()
|
||||
str_tmp_expr_advanced_var_decl()
|
||||
|
@ -159,6 +168,7 @@ fn main() {
|
|||
optional_str()
|
||||
optional_return()
|
||||
str_replace()
|
||||
str_replace2()
|
||||
if_cond()
|
||||
addition_with_tmp_expr()
|
||||
println('end')
|
||||
|
|
Loading…
Reference in New Issue