From a9435f3c25cc42d35359097473ffae102216a7c5 Mon Sep 17 00:00:00 2001 From: zakuro <z@kuro.red> Date: Thu, 13 May 2021 23:54:48 +0900 Subject: [PATCH] cgen: fix `cannot take rvalue` error of interface (#10040) --- vlib/v/gen/c/cgen.v | 76 +++++++++++++++++-------------- vlib/v/tests/interface_test.v | 6 +++ vlib/v/tests/sumtype_calls_test.v | 4 ++ 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 53368205d0..da6d1a275d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1768,6 +1768,26 @@ fn (mut g Gen) write_sumtype_casting_fn(got_ ast.Type, exp_ ast.Type) { g.auto_fn_definitions << sb.str() } +fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp_is_ptr bool, exp_styp string, got_is_ptr bool, got_styp string) { + mut rparen_n := 1 + if exp_is_ptr { + g.write('HEAP($exp_styp, ') + rparen_n++ + } + g.write('${fname}(') + if !got_is_ptr { + if !expr.is_lvalue() + || (expr is ast.Ident && is_simple_define_const((expr as ast.Ident).obj)) { + g.write('ADDR($got_styp, (') + rparen_n += 2 + } else { + g.write('&') + } + } + g.expr(expr) + g.write(')'.repeat(rparen_n)) +} + // use instead of expr() when you need to cast to a different type fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) { got_type := g.table.mktyp(got_type_raw) @@ -1787,18 +1807,9 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ && !expected_type.has_flag(.optional) { got_styp := g.cc_type(got_type, true) exp_styp := g.cc_type(expected_type, true) - if expected_is_ptr { - g.write('HEAP($exp_styp, ') - } - g.write('I_${got_styp}_to_Interface_${exp_styp}(') - if !got_is_ptr { - g.write('&') - } - g.expr(expr) - g.write(')') - if expected_is_ptr { - g.write(')') - } + fname := 'I_${got_styp}_to_Interface_$exp_styp' + g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, exp_styp, got_is_ptr, + got_styp) return } // cast to sum type @@ -1827,21 +1838,9 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ g.expr(expr) } else { g.write_sumtype_casting_fn(got_type, expected_type) - if expected_is_ptr { - g.write('HEAP($exp_sym.cname, ') - } - g.write('${got_sym.cname}_to_sumtype_${exp_sym.cname}(') - if !got_is_ptr { - g.write('ADDR($got_styp, (') - g.expr(expr) - g.write(')))') - } else { - g.expr(expr) - g.write(')') - } - if expected_is_ptr { - g.write(')') - } + fname := '${got_sym.cname}_to_sumtype_$exp_sym.cname' + g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, exp_sym.cname, + got_is_ptr, got_styp) } return } @@ -5113,11 +5112,6 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { */ field_expr := field.expr match field.expr { - ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral { - // "Simple" expressions are not going to need multiple statements, - // only the ones which are inited later, so it's safe to use expr_string - g.const_decl_simple_define(name, g.expr_string(field_expr)) - } ast.ArrayInit { if field.expr.is_fixed { styp := g.typ(field.expr.typ) @@ -5147,12 +5141,28 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { } } else { - g.const_decl_init_later(field.mod, name, field.expr, field.typ, false) + if is_simple_define_const(field) { + // "Simple" expressions are not going to need multiple statements, + // only the ones which are inited later, so it's safe to use expr_string + g.const_decl_simple_define(name, g.expr_string(field_expr)) + } else { + g.const_decl_init_later(field.mod, name, field.expr, field.typ, false) + } } } } } +fn is_simple_define_const(obj ast.ScopeObject) bool { + if obj is ast.ConstField { + return match obj.expr { + ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral { true } + else { false } + } + } + return false +} + fn (mut g Gen) const_decl_simple_define(name string, val string) { // Simple expressions should use a #define // so that we don't pollute the binary with unnecessary global vars diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index 317f510a9b..388fd555ad 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -7,6 +7,10 @@ mut: breed string } +fn new_cat(breed string) Cat { + return Cat{breed} +} + fn (c &Cat) name() string { if c.breed != '' { assert c.breed == 'Persian' @@ -101,10 +105,12 @@ fn test_perform_speak() { perform_speak(Cat{ breed: 'Persian' }) + perform_speak(new_cat('Persian')) perform_speak_on_ptr(cat) perform_speak_on_ptr(Cat{ breed: 'Persian' }) + perform_speak_on_ptr(new_cat('Persian')) handle_animals([dog, cat]) /* f := Foo { diff --git a/vlib/v/tests/sumtype_calls_test.v b/vlib/v/tests/sumtype_calls_test.v index 8a68736511..d2680f2647 100644 --- a/vlib/v/tests/sumtype_calls_test.v +++ b/vlib/v/tests/sumtype_calls_test.v @@ -56,9 +56,13 @@ fn test_sum_type_cast() { fn test_sum_types() { b := parse_bool() handle_expr(b) + handle_expr(parse_bool()) + de := DeclExprA{} handle_expr(de) handle_decl_expr(de) + handle_expr(DeclExprA{}) + handle_decl_expr(DeclExprA{}) } /*