v icon indicating copy to clipboard operation
v copied to clipboard

parser, cgen: fix option variable error (fix #17460)

Open yuyi98 opened this issue 2 years ago • 4 comments

This PR fix option variable error (fix #17460, fix #17461).

  • Fix option variable error.
  • Add test.
struct Foo {
	name ?string
}

fn main() {
	foo := Foo{}
	other := foo.name

	println(typeof(other).name)
	if name := other {
		println('with name: ${name}')
		assert false
	} else {
		println('without name')
		assert true
	}

	println(foo.name)
}

PS D:\Test\v\tt1> v run .
?string
without name
Option(error: none)
struct Foo {
	name ?string
}

fn main() {
	foo := Foo{}
	other := foo.name
	mut counter := 0
	val := other or {
		counter++
		'default'
	}

	assert val == 'default'
	assert counter == 1
}

PS D:\Test\v\tt1> v run .

yuyi98 avatar Mar 03 '23 03:03 yuyi98

Why does the second example print without name 2 times?

spytheman avatar Mar 03 '23 12:03 spytheman

it generated wrongly :-| :

    if (other.state != 0) {
        IError err = other.err;
        println(_SLIT("without name"));
        *(string*) other.data = _SLIT("default");
    }
    string val = /*opt*/(*(string*)other.data);
    if (other.state != 0) {
        println(_SLIT("without name"));
        val = _SLIT("default");
    }
    ;

The second if body should not be there, then it will produce the without name just once.

spytheman avatar Mar 03 '23 12:03 spytheman

Ok, I'll fix it.

yuyi98 avatar Mar 03 '23 12:03 yuyi98

Something like this can test it:

struct Foo {
	name ?string
}

fn test_or_block_should_be_evaluated_just_once() {
	foo := Foo{}
	other := foo.name
	mut counter := 0
	val := other or {
		counter++
		'default'
	}
	assert val == 'default'
	assert counter == 1
}

spytheman avatar Mar 03 '23 12:03 spytheman