From 2597efa7f670ab5b58e915c293423512381fbfa2 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 7 Mar 2023 17:53:56 -0300 Subject: [PATCH] cgen: fix struct initialization with option value (#17539) --- vlib/v/gen/c/assign.v | 2 +- vlib/v/gen/c/cgen.v | 3 +-- vlib/v/gen/c/struct.v | 20 +++++++++++++------ .../tests/option_struct_init_interface_test.v | 18 +++++++++++++++++ .../tests/option_struct_init_with_opt_test.v | 19 ++++++++++++++++++ 5 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 vlib/v/tests/option_struct_init_interface_test.v create mode 100644 vlib/v/tests/option_struct_init_with_opt_test.v diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 8ae0eb969c..8a1c7d3753 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -70,7 +70,7 @@ fn (mut g Gen) expr_opt_with_cast(expr ast.Expr, expr_typ ast.Type, ret_typ ast. } else { old_inside_opt_or_res := g.inside_opt_or_res g.inside_opt_or_res = false - g.expr(expr) + g.expr_with_cast(expr, expr_typ, ret_typ) g.inside_opt_or_res = old_inside_opt_or_res } g.writeln(' }, (${option_name}*)(&${tmp_var}), sizeof(${styp}));') diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c1308b3750..44895fa51e 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2260,8 +2260,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ return } if got_sym.info !is ast.Interface && exp_sym.info is ast.Interface - && got_type.idx() != expected_type.idx() && !expected_type.has_flag(.option) - && !expected_type.has_flag(.result) { + && got_type.idx() != expected_type.idx() && !expected_type.has_flag(.result) { if expr is ast.StructInit && !got_type.is_ptr() { g.inside_cast_in_heap++ got_styp := g.cc_type(got_type.ref(), true) diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index a8325912ee..525e427e79 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -336,12 +336,21 @@ fn (mut g Gen) zero_struct_field(field ast.StructField) bool { g.write('.${field_name} = ') if field.has_default_expr { if sym.kind in [.sum_type, .interface_] { - g.expr_with_cast(field.default_expr, field.default_expr_typ, field.typ) + if field.typ.has_flag(.option) { + g.expr_opt_with_cast(field.default_expr, field.default_expr_typ.set_flag(.option), + field.typ) + } else { + g.expr_with_cast(field.default_expr, field.default_expr_typ, field.typ) + } return true } - if (field.typ.has_flag(.option) && !field.default_expr_typ.has_flag(.option)) - || (field.typ.has_flag(.result) && !field.default_expr_typ.has_flag(.result)) { + if field.typ.has_flag(.option) { + tmp_var := g.new_tmp_var() + g.expr_with_tmp_var(field.default_expr, field.default_expr_typ, field.typ, + tmp_var) + return true + } else if field.typ.has_flag(.result) && !field.default_expr_typ.has_flag(.result) { tmp_var := g.new_tmp_var() g.expr_with_tmp_var(field.default_expr, field.default_expr_typ, field.typ, tmp_var) @@ -538,10 +547,9 @@ fn (mut g Gen) struct_init_field(sfield ast.StructInitField, language ast.Langua g.write('/* autoref */&') } - if (sfield.expected_type.has_flag(.option) && !sfield.typ.has_flag(.option)) + if sfield.expected_type.has_flag(.option) || (sfield.expected_type.has_flag(.result) && !sfield.typ.has_flag(.result)) { - tmp_var := g.new_tmp_var() - g.expr_with_tmp_var(sfield.expr, sfield.typ, sfield.expected_type, tmp_var) + g.expr_with_opt(sfield.expr, sfield.typ, sfield.expected_type) } else { g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type) } diff --git a/vlib/v/tests/option_struct_init_interface_test.v b/vlib/v/tests/option_struct_init_interface_test.v new file mode 100644 index 0000000000..c5f4c7aa73 --- /dev/null +++ b/vlib/v/tests/option_struct_init_interface_test.v @@ -0,0 +1,18 @@ +interface IPerson { + name string + age int +} + +struct PersonImpl { + name string + age int +} + +struct Person { + other ?IPerson = PersonImpl{} +} + +fn test_main() { + a := Person{} + assert a.other != none +} diff --git a/vlib/v/tests/option_struct_init_with_opt_test.v b/vlib/v/tests/option_struct_init_with_opt_test.v new file mode 100644 index 0000000000..7be9be3215 --- /dev/null +++ b/vlib/v/tests/option_struct_init_with_opt_test.v @@ -0,0 +1,19 @@ +struct Foo { + x ?string +} + +fn test_main() { + x := ?string('hi') + foo := Foo{ + x: x + } + assert foo.x? == 'hi' +} + +fn test_none() { + x := ?string(none) + foo := Foo{ + x: x + } + assert foo.x == none +}