From 90ba856107ca4516873aebb3a3b23bf1bd767e9b Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 20 Nov 2021 13:12:03 +0200 Subject: [PATCH] cgen: fix `dump(x)` with `fn (x &Type) str() string {` --- vlib/v/gen/c/auto_str_methods.v | 32 +++++++++++----------- vlib/v/gen/c/dumpexpr.v | 14 +++++----- vlib/v/tests/dump_fns_test.v | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 08f30a2f73..845179ac90 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -506,6 +506,7 @@ fn styp_to_str_fn_name(styp string) string { return styp.replace_each(['*', '', '.', '__', ' ', '__']) + '_str' } +// deref_kind returns deref, deref_label fn deref_kind(str_method_expects_ptr bool, is_elem_ptr bool, typ ast.Type) (string, string) { if str_method_expects_ptr != is_elem_ptr { if is_elem_ptr { @@ -823,9 +824,10 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri } // custom methods management - has_custom_str := sym.has_method('str') - mut field_styp := g.typ(field.typ).replace('*', '') - field_styp_fn_name := if has_custom_str { + sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() + sftyp := g.typ(field.typ) + mut field_styp := sftyp.replace('*', '') + field_styp_fn_name := if sym_has_str_method { '${field_styp}_str' } else { g.get_str_fn(field.typ) @@ -839,7 +841,8 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri fn_builder.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') } - mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name) + mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name, + sym_has_str_method, str_method_expects_ptr) if field.typ in ast.cptr_types { func = '(voidptr) it.$field.name' } else if field.typ.is_ptr() { @@ -875,29 +878,26 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri fn_builder.writeln('}') } -fn struct_auto_str_func1(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string { - has_custom_str, expects_ptr, _ := sym.str_method_info() +fn struct_auto_str_func1(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string, has_custom_str bool, expects_ptr bool) string { + deref, _ := deref_kind(expects_ptr, field_type.is_ptr(), field_type) if sym.kind == .enum_ { - return '${fn_name}(it.${c_name(field_name)})' + return '${fn_name}(${deref}it.${c_name(field_name)})' } else if should_use_indent_func(sym.kind) { - mut obj := 'it.${c_name(field_name)}' - if field_type.is_ptr() && !expects_ptr { - obj = '*$obj' - } + obj := 'it.${c_name(field_name)}' if has_custom_str { - return '${fn_name}($obj)' + return '${fn_name}($deref$obj)' } - return 'indent_${fn_name}($obj, indent_count + 1)' + return 'indent_${fn_name}($deref$obj, indent_count + 1)' } else if sym.kind in [.array, .array_fixed, .map, .sum_type] { if has_custom_str { - return '${fn_name}(it.${c_name(field_name)})' + return '${fn_name}(${deref}it.${c_name(field_name)})' } - return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)' + return 'indent_${fn_name}(${deref}it.${c_name(field_name)}, indent_count + 1)' } else if sym.kind == .function { return '${fn_name}()' } else { if sym.kind == .chan { - return '${fn_name}(it.${c_name(field_name)})' + return '${fn_name}(${deref}it.${c_name(field_name)})' } mut method_str := 'it.${c_name(field_name)}' if sym.kind == .bool { diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index b58e83d912..6ec56baefa 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -21,10 +21,12 @@ fn (mut g Gen) dump_expr_definitions() { mut dump_typedefs := map[string]bool{} mut dump_fns := strings.new_builder(100) for dump_type, cname in g.table.dumps { - to_string_fn_name := g.get_str_fn(dump_type) - is_ptr := ast.Type(dump_type).is_ptr() - ptr_asterisk := if is_ptr { '*' } else { '' } dump_sym := g.table.get_type_symbol(dump_type) + _, str_method_expects_ptr, _ := dump_sym.str_method_info() + is_ptr := ast.Type(dump_type).is_ptr() + deref, _ := deref_kind(str_method_expects_ptr, is_ptr, dump_type) + to_string_fn_name := g.get_str_fn(dump_type) + ptr_asterisk := if is_ptr { '*' } else { '' } mut str_dumparg_type := '$cname$ptr_asterisk' if dump_sym.kind == .function { fninfo := dump_sym.info as ast.FnType @@ -36,7 +38,7 @@ fn (mut g Gen) dump_expr_definitions() { dump_typedefs['typedef $str_tdef;'] = true } dump_fn_name := '_v_dump_expr_$cname' + (if is_ptr { '_ptr' } else { '' }) - if g.writeln_fn_header('$str_dumparg_type ${dump_fn_name}(string fpath, int line, string sexpr, $str_dumparg_type x)', mut + if g.writeln_fn_header('$str_dumparg_type ${dump_fn_name}(string fpath, int line, string sexpr, $str_dumparg_type dump_arg)', mut dump_fns) { continue @@ -52,8 +54,8 @@ fn (mut g Gen) dump_expr_definitions() { if is_ptr { dump_fns.writeln('\teprint(${ctoslit('&')});') } - dump_fns.writeln('\teprintln(${to_string_fn_name}(${ptr_asterisk}x));') - dump_fns.writeln('\treturn x;') + dump_fns.writeln('\teprintln(${to_string_fn_name}(${deref}dump_arg));') + dump_fns.writeln('\treturn dump_arg;') dump_fns.writeln('}') } for tdef, _ in dump_typedefs { diff --git a/vlib/v/tests/dump_fns_test.v b/vlib/v/tests/dump_fns_test.v index c56b1eff58..6a3838528a 100644 --- a/vlib/v/tests/dump_fns_test.v +++ b/vlib/v/tests/dump_fns_test.v @@ -20,3 +20,50 @@ fn test_dump_of_functions() { assert foo == x assert y == zoo } + +// + +struct StructWithStrMethodTakingReference { + x int +} + +pub fn (t &StructWithStrMethodTakingReference) str() string { + return 'StructWithStrMethodTakingReference{x: $t.x}' +} + +fn test_dump_of_type_that_has_custom_str_method_with_reference_parameter() { + s := StructWithStrMethodTakingReference{123} + assert dump(s).x == 123 + ps := &StructWithStrMethodTakingReference{456} + assert dump(ps).x == 456 +} + +// + +struct StructWithNormalStrMethod { + x int +} + +pub fn (t StructWithNormalStrMethod) str() string { + return 'StructWithNormalStrMethod{x: $t.x}' +} + +fn test_dump_of_type_that_has_normal_custom_str_method() { + s := StructWithNormalStrMethod{123} + assert dump(s).x == 123 + ps := &StructWithNormalStrMethod{456} + assert dump(ps).x == 456 +} + +// + +struct StructWithoutStrMethod { + x int +} + +fn test_dump_of_type_that_has_no_custom_str_method() { + s := StructWithoutStrMethod{123} + assert dump(s).x == 123 + ps := &StructWithoutStrMethod{456} + assert dump(ps).x == 456 +}