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