From 5b6eb7b2c926206f09bcbcd3739721e714bd6290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=C3=A4schle?= Date: Tue, 1 Dec 2020 16:09:03 +0100 Subject: [PATCH] cgen: simplify .str() generation (#7038) --- vlib/v/checker/check_types.v | 3 +- vlib/v/gen/auto_str_methods.v | 106 +++++++++---------------- vlib/v/gen/cgen.v | 107 +------------------------- vlib/v/gen/fn.v | 57 ++------------ vlib/v/gen/json.v | 1 - vlib/v/gen/str.v | 80 +++++++++++++++++-- vlib/v/tests/inout/nested_structs.out | 2 +- vlib/v/tests/struct_test.v | 4 +- 8 files changed, 123 insertions(+), 237 deletions(-) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 0b635815c0..24c3487914 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -327,7 +327,8 @@ pub fn (c &Checker) get_default_fmt(ftyp table.Type, typ table.Type) byte { } if ftyp in [table.string_type, table.bool_type] || sym.kind in - [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type] || sym.has_method('str') { + [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type, .none_] || ftyp.has_flag(.optional) || + sym.has_method('str') { return `s` } else { return `_` diff --git a/vlib/v/gen/auto_str_methods.v b/vlib/v/gen/auto_str_methods.v index 9d2daac00a..89f475d462 100644 --- a/vlib/v/gen/auto_str_methods.v +++ b/vlib/v/gen/auto_str_methods.v @@ -6,45 +6,21 @@ import v.table import v.pref import v.util -// already generated styp, reuse it -fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string { +fn (mut g Gen) gen_str_for_type(typ table.Type) string { + styp := g.typ(typ).replace('*', '') mut sym := g.table.get_type_symbol(g.unwrap_generic(typ)) mut str_fn_name := styp_to_str_fn_name(styp) if mut sym.info is table.Alias { if sym.info.is_import { sym = g.table.get_type_symbol(sym.info.parent_type) - str_fn_name = styp_to_str_fn_name(sym.name.replace('.', '__')) + str_fn_name = styp_to_str_fn_name(sym.name) } } sym_has_str_method, str_method_expects_ptr, str_nr_args := sym.str_method_info() - // generate for type - if sym_has_str_method && str_method_expects_ptr && str_nr_args == 1 { - // TODO: optimize out this. - // It is needed, so that println() can be called with &T and T has `fn (t &T).str() string` - /* - eprintln('>> gsftws: typ: $typ | typ_is_ptr $typ_is_ptr | styp: $styp ' + - '| $str_fn_name | sym.name: $sym.name has_str: $sym_has_str_method ' + - '| expects_ptr: $str_method_expects_ptr') - */ - str_fn_name_no_ptr := '${str_fn_name}_no_ptr' - already_generated_key_no_ptr := '$styp:$str_fn_name_no_ptr' - if already_generated_key_no_ptr !in g.str_types { - g.str_types << already_generated_key_no_ptr - g.type_definitions.writeln('static string ${str_fn_name_no_ptr}($styp it); // auto no_ptr version') - g.auto_str_funcs.writeln('static string ${str_fn_name_no_ptr}($styp it){ return ${str_fn_name}(&it); }') - } - /* - typ_is_ptr := typ.is_ptr() - ret_type := if typ_is_ptr { str_fn_name } else { str_fn_name_no_ptr } - eprintln(' ret_type: $ret_type') - return ret_type - */ - return str_fn_name_no_ptr - } already_generated_key := '$styp:$str_fn_name' if !sym_has_str_method && already_generated_key !in g.str_types && !typ.has_flag(.optional) { $if debugautostr ? { - eprintln('> gen_str_for_type_with_styp: |typ: ${typ:5}, ${sym.name:20}|has_str: ${sym_has_str_method:5}|expects_ptr: ${str_method_expects_ptr:5}|nr_args: ${str_nr_args:1}|fn_name: ${str_fn_name:20}') + eprintln('> gen_str_for_type: |typ: ${typ:5}, ${sym.name:20}|has_str: ${sym_has_str_method:5}|expects_ptr: ${str_method_expects_ptr:5}|nr_args: ${str_nr_args:1}|fn_name: ${str_fn_name:20}') } g.str_types << already_generated_key match mut sym.info { @@ -108,8 +84,7 @@ fn (mut g Gen) gen_str_for_option(typ table.Type, styp string, str_fn_name strin sym_name := sym.name.replace('.', '__') mut parent_str_fn_name := styp_to_str_fn_name(sym_name) if !sym_has_str_method { - parent_styp := g.typ(parent_type) - parent_str_fn_name = g.gen_str_for_type_with_styp(parent_type, parent_styp) + parent_str_fn_name = g.gen_str_for_type(parent_type) } g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto') g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }') @@ -138,8 +113,7 @@ fn (mut g Gen) gen_str_for_alias(info table.Alias, styp string, str_fn_name stri sym_has_str_method, _, _ := sym.str_method_info() mut parent_str_fn_name := styp_to_str_fn_name(sym.name.replace('.', '__')) if !sym_has_str_method { - parent_styp := g.typ(info.parent_type) - parent_str_fn_name = g.gen_str_for_type_with_styp(info.parent_type, parent_styp) + parent_str_fn_name = g.gen_str_for_type(info.parent_type) } mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.')) g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto') @@ -175,7 +149,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri elem_str_fn_name = styp_to_str_fn_name(field_styp) } if !sym_has_str_method { - g.gen_str_for_type_with_styp(typ, field_styp) + g.gen_str_for_type(typ) } g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}') @@ -240,7 +214,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_f elem_str_fn_name = styp_to_str_fn_name(field_styp) } if !sym.has_method('str') { - elem_str_fn_name = g.gen_str_for_type_with_styp(typ, field_styp) + elem_str_fn_name = g.gen_str_for_type(typ) } g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}') @@ -275,15 +249,14 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_f fn (mut g Gen) gen_str_for_map(info table.Map, styp string, str_fn_name string) { key_sym := g.table.get_type_symbol(info.key_type) - key_styp := g.typ(info.key_type) if !key_sym.has_method('str') { - g.gen_str_for_type_with_styp(info.key_type, key_styp) + g.gen_str_for_type(info.key_type) } val_sym := g.table.get_type_symbol(info.value_type) val_styp := g.typ(info.value_type) elem_str_fn_name := val_styp.replace('*', '') + '_str' if !val_sym.has_method('str') { - g.gen_str_for_type_with_styp(info.value_type, val_styp) + g.gen_str_for_type(info.value_type) } zero := g.type_default(info.value_type) g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto') @@ -339,8 +312,7 @@ fn (mut g Gen) gen_str_for_multi_return(info table.MultiReturn, styp string, str for typ in info.types { sym := g.table.get_type_symbol(typ) if !sym.has_method('str') { - field_styp := g.typ(typ) - g.gen_str_for_type_with_styp(typ, field_styp) + g.gen_str_for_type(typ) } } g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') @@ -397,15 +369,15 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st typ = typ.deref() } field_styp := g.typ(typ) - field_fn_name := g.gen_str_for_type_with_styp(field.typ, field_styp) + field_fn_name := g.gen_str_for_type(field.typ) fnames2strfunc[field_styp] = field_fn_name } } // _str() functions should have a single argument, the indenting ones take 2: - g.type_definitions.writeln('static string ${str_fn_name}($styp x); // auto') - g.auto_str_funcs.writeln('static string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x, 0);}') - g.type_definitions.writeln('static string indent_${str_fn_name}($styp x, int indent_count); // auto') - g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp x, int indent_count) {') + g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto') + g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0);}') + g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto') + g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {') mut clean_struct_v_type_name := styp.replace('__', '.') if clean_struct_v_type_name.contains('_T_') { // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ @@ -413,14 +385,6 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st clean_struct_v_type_name = clean_struct_v_type_name.replace('_T_', '<').replace('_', ', ') + '>' } - if styp.ends_with('*') { - deref_typ := styp.replace('*', '') - g.auto_str_funcs.writeln('\t$deref_typ *it = x;') - clean_struct_v_type_name = '&' + clean_struct_v_type_name.replace('*', '') - } else { - deref_typ := styp - g.auto_str_funcs.writeln('\t$deref_typ *it = &x;') - } clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) // generate ident / indent length = 4 spaces g.auto_str_funcs.writeln('\tstring indents = tos_lit("");') @@ -428,14 +392,12 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st g.auto_str_funcs.writeln('\t\tindents = string_add(indents, tos_lit(" "));') g.auto_str_funcs.writeln('\t}') if info.fields.len == 0 { - g.auto_str_funcs.write('\treturn tos_lit("$clean_struct_v_type_name{}");') + g.auto_str_funcs.write('\treturn _SLIT("$clean_struct_v_type_name{}");') } else { g.auto_str_funcs.write('\treturn _STR("$clean_struct_v_type_name{\\n"') for field in info.fields { - mut fmt := g.type_to_fmt(field.typ) - if field.typ.is_ptr() { - fmt = '&$fmt' - } + mut fmt := if field.typ.is_ptr() { '&' } else { '' } + fmt += g.type_to_fmt(field.typ) g.auto_str_funcs.writeln('\t\t"%.*s\\000 $field.name: $fmt\\n"') } g.auto_str_funcs.write('\t\t"%.*s\\000}", ${2 * (info.fields.len + 1)}') @@ -444,16 +406,14 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st for i, field in info.fields { sym := g.table.get_type_symbol(field.typ) has_custom_str := sym.has_method('str') - mut field_styp := g.typ(field.typ) - if field_styp.ends_with('*') { - field_styp = field_styp.replace('*', '') - } + mut field_styp := g.typ(field.typ).replace('*', '') field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] } g.auto_str_funcs.write('indents, ') func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name) + // reference types can be "nil" if field.typ.is_ptr() { - g.auto_str_funcs.write('isnil(it->${c_name(field.name)})') - g.auto_str_funcs.write(' ? tos_lit("nil") : ') + g.auto_str_funcs.write('isnil(it.${c_name(field.name)})') + g.auto_str_funcs.write(' ? _SLIT("nil") : ') // struct, floats and ints have a special case through the _str function if sym.kind != .struct_ && !field.typ.is_int() && !field.typ.is_float() { g.auto_str_funcs.write('*') @@ -474,9 +434,9 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name string, field_name string) string { has_custom_str := sym.has_method('str') if sym.kind == .enum_ { - return '${fn_name}(it->${c_name(field_name)})' + return '${fn_name}(it.${c_name(field_name)})' } else if sym.kind == .struct_ { - mut obj := 'it->${c_name(field_name)}' + mut obj := 'it.${c_name(field_name)}' if field_type.is_ptr() { obj = '*$obj' } @@ -486,11 +446,11 @@ fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name str return 'indent_${fn_name}($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}(it.${c_name(field_name)})' } - return 'indent_${fn_name}(it->${c_name(field_name)}, indent_count + 1)' + return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)' } else { - mut method_str := 'it->${c_name(field_name)}' + mut method_str := 'it.${c_name(field_name)}' if sym.kind == .bool { method_str += ' ? _SLIT("true") : _SLIT("false")' } else if (field_type.is_int() || field_type.is_float()) && field_type.is_ptr() { @@ -534,7 +494,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info table.SumType, styp string, str_f sym := g.table.get_type_symbol(typ) if !sym.has_method('str') { field_styp := g.typ(typ) - field_fn_name := g.gen_str_for_type_with_styp(typ, field_styp) + field_fn_name := g.gen_str_for_type(typ) gen_fn_names[field_styp] = field_fn_name } } @@ -555,8 +515,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info table.SumType, styp string, str_f value_fmt = "'$value_fmt'" } typ_str := g.typ(typ) - mut func_name := if typ_str in gen_fn_names { gen_fn_names[typ_str] } else { g.gen_str_for_type_with_styp(typ, - typ_str) } + mut func_name := if typ_str in gen_fn_names { gen_fn_names[typ_str] } else { g.gen_str_for_type(typ) } sym := g.table.get_type_symbol(typ) if sym.kind == .struct_ { func_name = 'indent_$func_name' @@ -571,3 +530,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info table.SumType, styp string, str_f g.auto_str_funcs.writeln('\t}') g.auto_str_funcs.writeln('}') } + +[inline] +fn styp_to_str_fn_name(styp string) string { + return styp.replace_each(['*', '', '.', '__']) + '_str' +} diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 168e2b8d8d..3a9683e276 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1453,9 +1453,7 @@ fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) { // without special casing ast.CastExpr here g.write(ctoslit(unknown_value)) } else { - g.gen_expr_to_string(e, t) or { - g.write(ctoslit('[$err]')) - } + g.gen_expr_to_string(e, t) } } ast.Type { @@ -1463,9 +1461,7 @@ fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) { g.write(ctoslit('$sym.name')) } else { - g.gen_expr_to_string(e, t) or { - g.write(ctoslit('[$err]')) - } + g.gen_expr_to_string(e, t) } } g.write(' /* typeof: ' + typeof(e) + ' type: ' + t.str() + ' */ ') @@ -4664,90 +4660,6 @@ fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol { return types_sorted } -fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool { - mut typ := etype - mut sym := g.table.get_type_symbol(typ) - if mut sym.info is table.Alias { - parent_sym := g.table.get_type_symbol(sym.info.parent_type) - if parent_sym.has_method('str') { - typ = sym.info.parent_type - sym = parent_sym - } - } - sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() - if typ.has_flag(.variadic) { - str_fn_name := g.gen_str_for_type(typ) - g.write('${str_fn_name}(') - g.expr(expr) - g.write(')') - } else if typ == table.string_type { - g.expr(expr) - } else if sym.kind == .enum_ { - is_var := match expr { - ast.SelectorExpr, ast.Ident { true } - else { false } - } - if is_var { - str_fn_name := g.gen_str_for_type(typ) - g.write('${str_fn_name}(') - g.enum_expr(expr) - g.write(')') - } else { - g.write('tos_lit("') - g.enum_expr(expr) - g.write('")') - } - } else if sym_has_str_method || sym.kind in - [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] { - is_p := typ.is_ptr() - val_type := if is_p { typ.deref() } else { typ } - str_fn_name := g.gen_str_for_type(val_type) - if is_p && str_method_expects_ptr { - g.write('string_add(_SLIT("&"), ${str_fn_name}((') - } - if is_p && !str_method_expects_ptr { - g.write('string_add(_SLIT("&"), ${str_fn_name}(*(') - } - if !is_p && !str_method_expects_ptr { - g.write('${str_fn_name}(') - } - if !is_p && str_method_expects_ptr { - g.write('${str_fn_name}(&') - } - if expr is ast.ArrayInit { - if expr.is_fixed { - s := g.typ(expr.typ) - g.write('($s)') - } - } - if expr is ast.CTempVar { - if expr.is_ptr { - g.write('*') - } - } - g.expr(expr) - if sym.kind == .struct_ && !sym_has_str_method { - if is_p { - g.write(')))') - } else { - g.write(')') - } - } else { - if is_p { - g.write(')))') - } else { - g.write(')') - } - } - } else { - str_fn_name := g.gen_str_for_type(typ) - g.write('${str_fn_name}(') - g.expr(expr) - g.write(')') - } - return true -} - // `nums.map(it % 2 == 0)` fn (mut g Gen) gen_array_map(node ast.CallExpr) { g.inside_lambda = true @@ -5555,21 +5467,6 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) { g.expr(node.right) } -[inline] -fn styp_to_str_fn_name(styp string) string { - return styp.replace('*', '_ptr') + '_str' -} - -[inline] -fn (mut g Gen) gen_str_for_type(typ table.Type) string { - // note: why was this here, removed for --usecache fix - // if g.pref.build_mode == .build_module { - // return '' - // } - styp := g.typ(typ) - return g.gen_str_for_type_with_styp(typ, styp) -} - fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name string) { mut convertor := '' mut typename_ := '' diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index b05738db9d..247a69502f 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -363,11 +363,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { return } if node.name == 'str' { - mut styp := g.typ(node.receiver_type) - if node.receiver_type.is_ptr() { - styp = styp.replace('*', '') - } - g.gen_str_for_type_with_styp(node.receiver_type, styp) + g.gen_str_for_type(node.receiver_type) } // TODO performance, detect `array` method differently if left_sym.kind == .array && node.name in @@ -549,55 +545,18 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } // check if alias parent also not a string if typ != table.string_type { - mut styp := g.typ(typ) - if typ.is_ptr() { - styp = styp.replace('*', '') - } - mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp) + expr := node.args[0].expr if g.autofree && !typ.has_flag(.optional) { // Create a temporary variable so that the value can be freed tmp := g.new_tmp_var() // tmps << tmp - g.write('string $tmp = ${str_fn_name}(') - g.expr(node.args[0].expr) - g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp') + g.write('string $tmp = ') + g.gen_expr_to_string(expr, typ) + g.writeln('; ${print_method}($tmp); string_free(&$tmp);') } else { - expr := node.args[0].expr - is_var := match expr { - ast.SelectorExpr { true } - ast.Ident { true } - else { false } - } - if typ.is_ptr() && sym.kind != .struct_ { - // ptr_str() for pointers - styp = 'ptr' - str_fn_name = 'ptr_str' - } - if sym.kind == .enum_ { - if is_var { - g.write('${print_method}(${str_fn_name}(') - } else { - // when no var, print string directly - g.write('${print_method}(tos3("') - } - if typ.is_ptr() { - // dereference - g.write('*') - } - g.enum_expr(expr) - if !is_var { - // end of string - g.write('"') - } - } else { - g.write('${print_method}(${str_fn_name}(') - if typ.is_ptr() && sym.kind == .struct_ { - // dereference - g.write('*') - } - g.expr(expr) - } - g.write('))') + g.write('${print_method}(') + g.gen_expr_to_string(expr, typ) + g.write(')') } print_auto_str = true } diff --git a/vlib/v/gen/json.v b/vlib/v/gen/json.v index f6caf551a3..34d7e6574d 100644 --- a/vlib/v/gen/json.v +++ b/vlib/v/gen/json.v @@ -239,7 +239,6 @@ fn (mut g Gen) encode_map(key_type table.Type, value_type table.Type) string { if key_type.is_string() { key += '(($styp*)${keys_tmp}.data)[i];' } else { - // g.gen_str_for_type(key_type) // key += '${styp}_str((($styp*)${keys_tmp}.data)[i]);' verror('json: encode only maps with string keys') } diff --git a/vlib/v/gen/str.v b/vlib/v/gen/str.v index aeb6651a82..ed7e911191 100644 --- a/vlib/v/gen/str.v +++ b/vlib/v/gen/str.v @@ -201,6 +201,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { break } g.write(escaped_val) + typ := g.unwrap_generic(node.expr_types[i]) // write correct format specifier to intermediate string g.write('%') fspec := node.fmts[i] @@ -214,7 +215,6 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { if node.precisions[i] != 987698 { fmt = '${fmt}.${node.precisions[i]}' } - typ := g.unwrap_generic(node.expr_types[i]) if fspec == `s` { if node.fwidths[i] == 0 { g.write('.*s') @@ -268,12 +268,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { } else { g.expr(expr) } - } else if typ.has_flag(.variadic) { - g.gen_expr_to_string(expr, typ) - } else if typ == table.bool_type { - g.expr(expr) - g.write(' ? _SLIT("true") : _SLIT("false")') - } else if node.fmts[i] == `s` { + } else if node.fmts[i] == `s` || typ.has_flag(.variadic) { g.gen_expr_to_string(expr, typ) } else if typ.is_number() || typ.is_pointer() || node.fmts[i] == `d` { if typ.is_signed() && node.fmts[i] in [`x`, `X`, `o`] { @@ -304,3 +299,74 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { } g.write(')') } + +fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) { + mut typ := etype + mut sym := g.table.get_type_symbol(typ) + // when type is alias, print the aliased value + if mut sym.info is table.Alias { + parent_sym := g.table.get_type_symbol(sym.info.parent_type) + if parent_sym.has_method('str') { + typ = sym.info.parent_type + sym = parent_sym + } + } + sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() + if typ.has_flag(.variadic) { + str_fn_name := g.gen_str_for_type(typ) + g.write('${str_fn_name}(') + g.expr(expr) + g.write(')') + } else if typ == table.string_type { + g.expr(expr) + } else if typ == table.bool_type { + g.expr(expr) + g.write(' ? _SLIT("true") : _SLIT("false")') + } else if sym.kind == .none_ { + g.write('_SLIT("none")') + } else if sym.kind == .enum_ { + is_var := match expr { + ast.SelectorExpr, ast.Ident { true } + else { false } + } + if is_var { + str_fn_name := g.gen_str_for_type(typ) + g.write('${str_fn_name}(') + g.enum_expr(expr) + g.write(')') + } else { + g.write('_SLIT("') + g.enum_expr(expr) + g.write('")') + } + } else if sym_has_str_method || sym.kind in + [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] { + is_ptr := typ.is_ptr() + str_fn_name := g.gen_str_for_type(typ) + if is_ptr { + g.write('_STR("&%.*s\\000", 2, ') + } + g.write('${str_fn_name}(') + if str_method_expects_ptr && !is_ptr { + g.write('&') + } else if !str_method_expects_ptr && is_ptr { + g.write('*') + } + if expr is ast.ArrayInit { + if expr.is_fixed { + s := g.typ(expr.typ) + g.write('($s)') + } + } + g.expr(expr) + g.write(')') + if is_ptr { + g.write(')') + } + } else { + str_fn_name := g.gen_str_for_type(typ) + g.write('${str_fn_name}(') + g.expr(expr) + g.write(')') + } +} diff --git a/vlib/v/tests/inout/nested_structs.out b/vlib/v/tests/inout/nested_structs.out index d8ea7a437d..f599475c2a 100644 --- a/vlib/v/tests/inout/nested_structs.out +++ b/vlib/v/tests/inout/nested_structs.out @@ -5,7 +5,7 @@ Aaa{ name: '' } } -Bbb{ +&Bbb{ pass: false name: '' } \ No newline at end of file diff --git a/vlib/v/tests/struct_test.v b/vlib/v/tests/struct_test.v index c52ab337b9..12015dd43e 100644 --- a/vlib/v/tests/struct_test.v +++ b/vlib/v/tests/struct_test.v @@ -205,7 +205,7 @@ pub mut: } fn fooo() { - a := AttrTest{1, 2, 3, 4, 5, 6} + _ := AttrTest{1, 2, 3, 4, 5, 6} } /* @@ -275,7 +275,7 @@ struct Country { } fn test_levels() { - c := Country{ + _ := Country{ name: 'UK' capital: { name: 'London'