v.gen.c: fix assert `f().len == 1` calling f() twice (closes issue 11501)

pull/11519/head
Delyan Angelov 2021-09-16 15:24:38 +03:00
parent c175b4fd48
commit 0a18690a4f
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
6 changed files with 113 additions and 14 deletions

View File

@ -12,19 +12,11 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
mut node := original_assert_statement
g.writeln('// assert')
if mut node.expr is ast.InfixExpr {
if mut node.expr.left is ast.CallExpr {
node.expr.left = g.new_ctemp_var_then_gen(node.expr.left, node.expr.left_type)
} else if mut node.expr.left is ast.ParExpr {
if node.expr.left.expr is ast.CallExpr {
node.expr.left = g.new_ctemp_var_then_gen(node.expr.left.expr, node.expr.left_type)
}
}
if mut node.expr.right is ast.CallExpr {
node.expr.right = g.new_ctemp_var_then_gen(node.expr.right, node.expr.right_type)
} else if mut node.expr.right is ast.ParExpr {
if node.expr.right.expr is ast.CallExpr {
node.expr.right = g.new_ctemp_var_then_gen(node.expr.right.expr, node.expr.right_type)
if subst_expr := g.assert_subexpression_to_ctemp(node.expr.left, node.expr.left_type) {
node.expr.left = subst_expr
}
if subst_expr := g.assert_subexpression_to_ctemp(node.expr.right, node.expr.right_type) {
node.expr.right = subst_expr
}
}
g.inside_ternary++
@ -60,6 +52,39 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
}
}
struct UnsupportedAssertCtempTransform {
msg string
code int
}
const unsupported_ctemp_assert_transform = IError(UnsupportedAssertCtempTransform{})
fn (mut g Gen) assert_subexpression_to_ctemp(expr ast.Expr, expr_type ast.Type) ?ast.Expr {
match expr {
ast.CallExpr {
return g.new_ctemp_var_then_gen(expr, expr_type)
}
ast.ParExpr {
if expr.expr is ast.CallExpr {
return g.new_ctemp_var_then_gen(expr.expr, expr_type)
}
}
ast.SelectorExpr {
if expr.expr is ast.CallExpr {
sym := g.table.get_final_type_symbol(g.unwrap_generic(expr.expr.return_type))
if sym.kind == .struct_ {
if (sym.info as ast.Struct).is_union {
return c.unsupported_ctemp_assert_transform
}
}
return g.new_ctemp_var_then_gen(expr, expr_type)
}
}
else {}
}
return c.unsupported_ctemp_assert_transform
}
fn (mut g Gen) gen_assert_postfailure_mode(node ast.AssertStmt) {
g.write_v_source_line_info(node.pos)
match g.pref.assert_failure_mode {

View File

@ -0,0 +1,9 @@
int _t1 = main__fn_returning_array().len;
if (!(_t1 == 1)) {
v_assert_meta_info__t2.src = _SLIT("fn_returning_array().len == 1");
v_assert_meta_info__t2.llabel = _SLIT("fn_returning_array().len");
int _t3 = main__fn_returning_struct().x;
if (!(_t3 == 123)) {
v_assert_meta_info__t4.src = _SLIT("fn_returning_struct().x == 123");
v_assert_meta_info__t4.llabel = _SLIT("fn_returning_struct().x");

View File

@ -0,0 +1,4 @@
[1]
Abc{
x: 123
}

View File

@ -0,0 +1,18 @@
struct Abc {
x int
}
fn fn_returning_array() []int {
return [1]
}
fn fn_returning_struct() Abc {
return Abc{123}
}
fn main() {
assert fn_returning_array().len == 1
assert fn_returning_struct().x == 123
println(fn_returning_array())
println(fn_returning_struct())
}

View File

@ -39,7 +39,9 @@ pub fn new_sourcemap(file string, source_root string, sources_content_inline boo
// Add a single mapping from original source line and column to the generated source's line and column for this source map being created.
pub fn (mut sm SourceMap) add_mapping(source_name string, source_position SourcePositionType, gen_line u32, gen_column u32, name string) {
assert source_name.len != 0
if source_name.len == 0 {
panic('add_mapping, source_name should not be ""')
}
sources_ind := sm.sources.add(source_name)
@ -53,7 +55,9 @@ pub fn (mut sm SourceMap) add_mapping(source_name string, source_position Source
// Add multiple mappings from the same source
pub fn (mut sm SourceMap) add_mapping_list(source_name string, mapping_list []MappingInput) ? {
assert source_name.len != 0
if source_name.len == 0 {
panic('add_mapping_list, source_name should not be ""')
}
sources_ind := sm.sources.add(source_name)

View File

@ -0,0 +1,39 @@
struct Abc {
ncalls int
}
[unsafe]
fn fn_that_should_be_called_just_once_array() []int {
mut static ncalls := 0
ncalls++
println('${@FN} calls: $ncalls')
if ncalls > 1 {
assert false
}
return []int{len: ncalls, init: ncalls}
}
[unsafe]
fn fn_that_should_be_called_just_once_struct() Abc {
mut static ncalls := 0
ncalls++
println('${@FN} calls: $ncalls')
if ncalls > 1 {
assert false
}
return Abc{
ncalls: ncalls
}
}
fn test_assert_calls_a_function_returning_an_array_just_once() {
unsafe {
assert fn_that_should_be_called_just_once_array().len == 1
}
}
fn test_assert_calls_a_function_returning_a_struct_just_once() {
unsafe {
assert fn_that_should_be_called_just_once_struct().ncalls == 1
}
}