From f30d0ce66732dfae32d3a85d14b18be9594a0a5c Mon Sep 17 00:00:00 2001
From: Alexander Medvednikov <alexander@medvednikov.com>
Date: Sun, 10 Nov 2019 21:54:28 +0300
Subject: [PATCH] parser: fix a bug with complex ref fn args

---
 vlib/compiler/compile_errors.v | 12 ++++++++++
 vlib/compiler/fn.v             | 41 +++++++++++++++++++++++++---------
 vlib/compiler/tests/fn_test.v  | 28 +++++++++++++++++++++++
 vlib/time/time.v               |  3 +--
 4 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/vlib/compiler/compile_errors.v b/vlib/compiler/compile_errors.v
index e1b39acd2e..eff44435e4 100644
--- a/vlib/compiler/compile_errors.v
+++ b/vlib/compiler/compile_errors.v
@@ -270,6 +270,18 @@ fn (s mut Scanner) eat_single_newline(){
 
 ///////////////////////////////
 
+fn (p mut Parser) mutable_arg_error(i int, arg Var, f Fn) {
+	mut dots_example :=  'mut $p.lit'
+	if i > 0 {
+		dots_example = '.., ' + dots_example
+	}
+	if i < f.args.len - 1 {
+		dots_example = dots_example + ',..'
+	}
+	p.error('`$arg.name` is a mutable argument, you need to provide `mut`: ' +
+			'`$f.name($dots_example)`')
+}	
+
 const (
 	warn_match_arrow = '=> is no longer needed in match statements, use\n' +
 'match foo {
diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v
index c363d59567..3104686cf0 100644
--- a/vlib/compiler/fn.v
+++ b/vlib/compiler/fn.v
@@ -931,8 +931,23 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
 		// Skip the receiver, because it was already generated in the expression
 		if i == 0 && f.is_method {
 			if f.args.len > 1 { // && !p.is_js {
-				p.gen(',')
+				p.gen(', ')
 			}
+			//if f.args[0].typ.ends_with('*') {
+			//p.gen('&/*119*/')
+			//}
+			/*
+			pos := p.cgen.cur_line.index('/* ? */')
+			if pos > -1 {
+				expr := p.cgen.cur_line[pos..]
+				// TODO hack
+				// If current expression is a func call, generate the array hack
+				if expr.contains('(') {
+					p.cgen.set_placeholder(pos, '(${arg.typ[..arg.typ.len-1]}[]){')
+					p.gen('}[0] ')
+				}
+			}
+			*/
 			continue
 		}
 		// Reached the final vararg? Quit
@@ -948,14 +963,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
 		// `mut numbers := [1,2,3]; reverse(mut numbers);`
 		if arg.is_mut {
 			if p.tok != .key_mut && p.tok == .name {
-				mut dots_example :=  'mut $p.lit'
-				if i > 0 {
-					dots_example = '.., ' + dots_example
-				}
-				if i < f.args.len - 1 {
-					dots_example = dots_example + ',..'
-				}
-				p.error('`$arg.name` is a mutable argument, you need to provide `mut`: `$f.name($dots_example)`')
+				p.mutable_arg_error(i, arg, f)
 			}
 			if p.peek() != .name {
 				p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
@@ -1105,13 +1113,26 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
 					p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
 					p.gen('}[0] ')
 				}
+				else if exp_ptr && expected == got + '*' {
+					expr := p.cgen.cur_line[ph..]
+					// TODO hack
+					// If current expression is a func call, generate the array hack
+					if expr.contains('(') {
+						//println('fn hack expr=$expr')
+						p.cgen.set_placeholder(ph, '& /*113 e="$expected" g="$got"*/ ($got[]){')
+						p.gen('}[0] ')
+					} else {
+						p.cgen.set_placeholder(ph, '& /*114*/')
+					}
+					
+				}	
 				// println('\ne:"$expected" got:"$got"')
 				else if ! (expected == 'void*' && got == 'int') &&
 				! (expected == 'byte*' && got.contains(']byte')) &&
 				! (expected == 'byte*' && got == 'string') &&
 				//! (expected == 'void*' && got == 'array_int') {
 				! (expected == 'byte*' && got == 'byteptr') {
-					p.cgen.set_placeholder(ph, '& /*112 EXP:"$expected" GOT:"$got" */')
+					p.cgen.set_placeholder(ph, '& /*112 e="$expected" g="$got" */')
 				}
 			}
 		}
diff --git a/vlib/compiler/tests/fn_test.v b/vlib/compiler/tests/fn_test.v
index 7125af85af..196e62bad1 100644
--- a/vlib/compiler/tests/fn_test.v
+++ b/vlib/compiler/tests/fn_test.v
@@ -21,6 +21,8 @@ multi line comment (3)
 	multi line comment (2)
 */
 
+import time
+
 type myfn fn (int) string
 
 type myfn2 fn (a int, b int) int
@@ -119,3 +121,29 @@ fn test_fns() {
 	// no asserts for now, just test function declarations above
 }
 
+struct Foo {
+}
+
+
+fn process_foo(foo &Foo) {
+}
+
+fn get_foo() Foo {
+        return Foo{}
+}
+
+
+// This used to be broken.
+fn test_ref_fn_arg() {
+	process_foo(get_foo())
+	println(3434)
+	assert true
+	
+	/*
+	res := (time.random().calc_unix())
+	println(res)
+	assert true
+	*/
+	
+}	
+
diff --git a/vlib/time/time.v b/vlib/time/time.v
index 07e5596a10..944ed0efd6 100644
--- a/vlib/time/time.v
+++ b/vlib/time/time.v
@@ -110,7 +110,6 @@ pub fn now() Time {
 pub fn random() Time {
 	now_unix := now().uni
 	rand_unix := rand.next(now_unix)
-
 	return time.unix(rand_unix)
 }
 
@@ -275,7 +274,7 @@ pub fn (t Time) ddmmy() string {
 // @return  string
 // @example Jul 3
 pub fn (t Time) md() string {
-        return t.get_fmt_date_str(.space, .mmmd) 
+        return t.get_fmt_date_str(.space, .mmmd)
 }
 
 pub fn (t Time) clean() string {