v.gen.c: fix assert `f().len == 1` calling f() twice (closes issue 11501)
parent
c175b4fd48
commit
0a18690a4f
|
@ -12,19 +12,11 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
|
||||||
mut node := original_assert_statement
|
mut node := original_assert_statement
|
||||||
g.writeln('// assert')
|
g.writeln('// assert')
|
||||||
if mut node.expr is ast.InfixExpr {
|
if mut node.expr is ast.InfixExpr {
|
||||||
if mut node.expr.left is ast.CallExpr {
|
if subst_expr := g.assert_subexpression_to_ctemp(node.expr.left, node.expr.left_type) {
|
||||||
node.expr.left = g.new_ctemp_var_then_gen(node.expr.left, node.expr.left_type)
|
node.expr.left = subst_expr
|
||||||
} 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.right, node.expr.right_type) {
|
||||||
|
node.expr.right = subst_expr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.inside_ternary++
|
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) {
|
fn (mut g Gen) gen_assert_postfailure_mode(node ast.AssertStmt) {
|
||||||
g.write_v_source_line_info(node.pos)
|
g.write_v_source_line_info(node.pos)
|
||||||
match g.pref.assert_failure_mode {
|
match g.pref.assert_failure_mode {
|
||||||
|
|
|
@ -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");
|
|
@ -0,0 +1,4 @@
|
||||||
|
[1]
|
||||||
|
Abc{
|
||||||
|
x: 123
|
||||||
|
}
|
|
@ -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())
|
||||||
|
}
|
|
@ -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.
|
// 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) {
|
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)
|
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
|
// Add multiple mappings from the same source
|
||||||
pub fn (mut sm SourceMap) add_mapping_list(source_name string, mapping_list []MappingInput) ? {
|
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)
|
sources_ind := sm.sources.add(source_name)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue