cgen: fix auto_str for option values (#17910)

This commit is contained in:
Felipe Pena 2023-04-10 00:56:57 -03:00 committed by GitHub
parent 220b31bfba
commit 5c439b6621
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 93 additions and 36 deletions

View File

@ -3,6 +3,6 @@
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): 1 [vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): 1
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): Option(0) [vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): Option(0)
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): struct { [vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): struct {
i: 100 i: Option(100)
} }
ok ok

View File

@ -192,13 +192,9 @@ fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string)
} else { } else {
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}(*(${sym.cname}*)it.data);') g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}(*(${sym.cname}*)it.data);')
} }
g.auto_str_funcs.writeln('\t} else {') g.auto_str_funcs.writeln('\t\treturn ${str_intp_sub('Option(%%)', 'res')};')
tmp_str := str_intp_sub('error: %%', 'IError_str(it.err)')
g.auto_str_funcs.writeln('\t\tres = ${tmp_str};')
g.auto_str_funcs.writeln('\t}') g.auto_str_funcs.writeln('\t}')
g.auto_str_funcs.writeln('\treturn _SLIT("Option(none)");')
g.auto_str_funcs.writeln('\treturn ${str_intp_sub('Option(%%)', 'res')};')
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
@ -231,7 +227,7 @@ fn (mut g Gen) gen_str_for_result(typ ast.Type, styp string, str_fn_name string)
g.auto_str_funcs.writeln('\t\tres = ${tmp_str};') g.auto_str_funcs.writeln('\t\tres = ${tmp_str};')
g.auto_str_funcs.writeln('\t}') g.auto_str_funcs.writeln('\t}')
g.auto_str_funcs.writeln('\treturn ${str_intp_sub('result(%%)', 'res')};') g.auto_str_funcs.writeln('\treturn ${str_intp_sub('Result(%%)', 'res')};')
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
@ -897,17 +893,20 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, typ_str string,
'' ''
} }
base_fmt := g.type_to_fmt(g.unwrap_generic(field.typ)) base_fmt := g.type_to_fmt(g.unwrap_generic(field.typ))
is_opt_field := field.typ.has_flag(.option)
// manage prefix and quote symbol for the filed // manage prefix and quote symbol for the filed
mut quote_str := '' mut quote_str := ''
mut prefix := '' mut prefix := ''
sym := g.table.sym(g.unwrap_generic(field.typ)) sym := g.table.sym(g.unwrap_generic(field.typ))
if !is_opt_field {
if sym.kind == .string { if sym.kind == .string {
quote_str = "'" quote_str = "'"
} else if field.typ in ast.charptr_types { } else if field.typ in ast.charptr_types {
quote_str = '\\"' quote_str = '\\"'
prefix = 'C' prefix = 'C'
} }
}
if is_first { if is_first {
// first field doesn't need \n // first field doesn't need \n
@ -937,7 +936,9 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, typ_str string,
g.get_str_fn(ftyp_noshared) g.get_str_fn(ftyp_noshared)
} }
// with floats we use always the g representation: // with floats we use always the g representation:
if sym.kind !in [.f32, .f64] { if is_opt_field {
fn_body.write_string('{_SLIT("${quote_str}"), ${c.si_s_code}, {.d_s=')
} else if sym.kind !in [.f32, .f64] {
fn_body.write_string('{_SLIT("${quote_str}"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') fn_body.write_string('{_SLIT("${quote_str}"), ${int(base_fmt)}, {.${data_str(base_fmt)}=')
} else { } else {
g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex()
@ -949,8 +950,11 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, typ_str string,
field.name, sym_has_str_method, str_method_expects_ptr) field.name, sym_has_str_method, str_method_expects_ptr)
ftyp_nr_muls := field.typ.nr_muls() ftyp_nr_muls := field.typ.nr_muls()
if ftyp_nr_muls > 1 || field.typ in ast.cptr_types { if ftyp_nr_muls > 1 || field.typ in ast.cptr_types {
if is_opt_field {
} else {
func = '(voidptr) it.${field.name}' func = '(voidptr) it.${field.name}'
caller_should_free = false caller_should_free = false
}
} else if ftyp_noshared.is_ptr() { } else if ftyp_noshared.is_ptr() {
// reference types can be "nil" // reference types can be "nil"
if ftyp_noshared.has_flag(.option) { if ftyp_noshared.has_flag(.option) {
@ -1004,7 +1008,7 @@ fn struct_auto_str_func(sym &ast.TypeSymbol, _field_type ast.Type, fn_name strin
deref, _ := deref_kind(expects_ptr, field_type.is_ptr(), field_type) deref, _ := deref_kind(expects_ptr, field_type.is_ptr(), field_type)
if sym.kind == .enum_ { if sym.kind == .enum_ {
return '${fn_name}(${deref}(it.${c_name(field_name)}))', true return '${fn_name}(${deref}(it.${c_name(field_name)}))', true
} else if should_use_indent_func(sym.kind) { } else if _field_type.has_flag(.option) || should_use_indent_func(sym.kind) {
obj := '${deref}it.${c_name(field_name)}${sufix}' obj := '${deref}it.${c_name(field_name)}${sufix}'
if has_custom_str { if has_custom_str {
return '${fn_name}(${obj})', true return '${fn_name}(${obj})', true

View File

@ -1,10 +1,10 @@
0 0
0 0
Option(error: none) Option(none)
Option(error: none) Option(none)
Option(error: none) Option(none)
Option(error: none) Option(none)
1 1
1 1
println(NIL) println(NIL)
Option(error: none) Option(none)

View File

@ -0,0 +1,18 @@
Test{
a: Option(none)
b: Option(none)
c: Option(none)
d: &Option(none)
e: Option(none)
f: Option(none)
g: Option(none)
h: &Option(none)
i: Option(none)
j: Option(none)
k: []
l: []
m: []
n: Option(Other{
a: Option(none)
})
}

View File

@ -0,0 +1,35 @@
type Alias = int
type SumType = int | string
enum Abc {
a
b
c
}
struct Other {
a ?int
}
struct Test {
a ?int
b ?string
c ?[]int
d ?&int
e ?Alias
f ?SumType
g ?Other
h ?&&int
i ?Abc
j ?fn (int)
k []?int
l []?string
m []?Other
n ?Other = Other{}
}
fn main() {
t := Test{}
println(t)
}

View File

@ -16,11 +16,11 @@
none none
3 3
Foo{ Foo{
bar: 3 bar: Option(3)
baz: 0 baz: Option(none)
} }
[vlib/v/slow_tests/inout/struct_field_option.vv:61] f: Foo{ [vlib/v/slow_tests/inout/struct_field_option.vv:61] f: Foo{
bar: 3 bar: Option(3)
baz: 0 baz: Option(none)
} }
1 1

View File

@ -24,7 +24,7 @@ fn f_arr2(args ?[3]f64) ?[]f64 {
fn test_simple() { fn test_simple() {
mut arr := ?[3]int(none) mut arr := ?[3]int(none)
println(arr) // Option(error: none) println(arr) // Option(none)
} }
fn test_simple_assign() { fn test_simple_assign() {

View File

@ -15,6 +15,6 @@ fn test_main() {
} }
assert a.str() == 'MyStruct2{ assert a.str() == 'MyStruct2{
valuea: 1 valuea: 1
valueb: Option(error: none) valueb: Option(none)
}' }'
} }

View File

@ -21,7 +21,7 @@ fn test_return_err_var() {
} }
fn test_str() { fn test_str() {
assert '${foo()}' == 'result(1)' assert '${foo()}' == 'Result(1)'
} }
fn result_void(err bool) ! { fn result_void(err bool) ! {

View File

@ -328,12 +328,12 @@ fn test_multi_generic_struct() {
assert x.str() == 'MultiGenericStruct[TestStruct, TestStruct]{\n t: TestStruct{\n x: 0\n }\n x: TestStruct{\n x: 0\n }\n}' assert x.str() == 'MultiGenericStruct[TestStruct, TestStruct]{\n t: TestStruct{\n x: 0\n }\n x: TestStruct{\n x: 0\n }\n}'
} }
fn create_option_err() ?string { fn create_option_err() !string {
return error('this is an error') return error('this is an error')
} }
fn test_option_err() { fn test_result_err() {
assert '${create_option_err()}' == 'Option(error: this is an error)' assert '${create_option_err()}' == 'Result(error: this is an error)'
} }
fn create_option_none() ?string { fn create_option_none() ?string {
@ -341,7 +341,7 @@ fn create_option_none() ?string {
} }
fn test_option_none() { fn test_option_none() {
assert '${create_option_none()}' == 'Option(error: none)' assert '${create_option_none()}' == 'Option(none)'
} }
fn create_option_string() ?string { fn create_option_string() ?string {

View File

@ -155,7 +155,7 @@ fn (e &Encoder) encode_struct[U](val U, level int, mut wr io.Writer) ! {
mut i := 0 mut i := 0
mut fields_len := 0 mut fields_len := 0
$for field in U.fields { $for field in U.fields {
if val.$(field.name).str() != 'Option(error: none)' { if val.$(field.name).str() != 'Option(none)' {
fields_len++ fields_len++
} }
} }
@ -171,7 +171,7 @@ fn (e &Encoder) encode_struct[U](val U, level int, mut wr io.Writer) ! {
} }
$if field.is_option { $if field.is_option {
is_none := value.str() == 'Option(error: none)' is_none := value.str() == 'Option(none)'
if !is_none { if !is_none {
e.encode_newline(level, mut wr)! e.encode_newline(level, mut wr)!