Skip to content

Commit 8e47c21

Browse files
authored
cgen: fix if guard stmts return generated code + fix auto generated option map comparison code (#20169)
1 parent 55061e4 commit 8e47c21

File tree

3 files changed

+98
-19
lines changed

3 files changed

+98
-19
lines changed

vlib/v/gen/c/auto_eq_methods.v

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,26 @@ fn (mut g Gen) read_field(struct_type ast.Type, field_name string, var_name stri
126126
}
127127
}
128128

129+
// read_map generates C code for reading option/no-option struct field
130+
@[inline]
131+
fn (mut g Gen) read_map_from_option(typ ast.Type, var_name string) string {
132+
return if typ.has_flag(.option) {
133+
return '(${g.base_type(typ)}*)&${var_name}.data'
134+
} else {
135+
var_name
136+
}
137+
}
138+
139+
// read_map_field generates C code for reading option/no-option struct field
140+
@[inline]
141+
fn (mut g Gen) read_map_field_from_option(typ ast.Type, field_name string, var_name string) string {
142+
return if typ.has_flag(.option) {
143+
'(*(${g.base_type(typ)}*)${var_name}.data).${field_name}'
144+
} else {
145+
'${var_name}.${field_name}'
146+
}
147+
}
148+
129149
// read_opt_field generates C code for reading option/no-option struct field
130150
@[inline]
131151
fn (mut g Gen) read_opt_field(struct_type ast.Type, field_name string, var_name string, field_typ ast.Type) string {
@@ -136,6 +156,16 @@ fn (mut g Gen) read_opt_field(struct_type ast.Type, field_name string, var_name
136156
}
137157
}
138158

159+
// read_map_opt_field generates C code for reading option/no-option map field
160+
@[inline]
161+
fn (mut g Gen) read_map_opt_field(struct_type ast.Type, field_name string, var_name string, field_typ ast.Type) string {
162+
return if field_typ.has_flag(.option) {
163+
'*(${g.base_type(field_typ)}*)${g.read_field(struct_type, field_name, var_name)}.data'
164+
} else {
165+
g.read_field(struct_type, field_name, var_name)
166+
}
167+
}
168+
139169
fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string {
140170
left := g.unwrap(left_type)
141171
ptr_styp := g.typ(left.typ.set_nr_muls(0))
@@ -429,64 +459,71 @@ fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string {
429459
ptr_value_styp := g.typ(value.typ)
430460
g.definitions.writeln('static bool ${ptr_styp}_map_eq(${ptr_styp} a, ${ptr_styp} b); // auto')
431461

462+
left_len := g.read_map_field_from_option(left.typ, 'len', 'a')
463+
right_len := g.read_map_field_from_option(left.typ, 'len', 'b')
464+
key_values := g.read_map_field_from_option(left.typ, 'key_values', 'a')
465+
466+
a := if left.typ.has_flag(.option) { g.read_map_from_option(left.typ, 'a') } else { '&a' }
467+
b := if left.typ.has_flag(.option) { g.read_map_from_option(left.typ, 'b') } else { '&b' }
468+
432469
mut fn_builder := strings.new_builder(512)
433470
fn_builder.writeln('static bool ${ptr_styp}_map_eq(${ptr_styp} a, ${ptr_styp} b) {')
434-
fn_builder.writeln('\tif (a.len != b.len) {')
471+
fn_builder.writeln('\tif (${left_len} != ${right_len}) {')
435472
fn_builder.writeln('\t\treturn false;')
436473
fn_builder.writeln('\t}')
437-
fn_builder.writeln('\tfor (int i = 0; i < a.key_values.len; ++i) {')
438-
fn_builder.writeln('\t\tif (!DenseArray_has_index(&a.key_values, i)) continue;')
439-
fn_builder.writeln('\t\tvoidptr k = DenseArray_key(&a.key_values, i);')
440-
fn_builder.writeln('\t\tif (!map_exists(&b, k)) return false;')
474+
fn_builder.writeln('\tfor (int i = 0; i < ${key_values}.len; ++i) {')
475+
fn_builder.writeln('\t\tif (!DenseArray_has_index(&${key_values}, i)) continue;')
476+
fn_builder.writeln('\t\tvoidptr k = DenseArray_key(&${key_values}, i);')
477+
fn_builder.writeln('\t\tif (!map_exists(${b}, k)) return false;')
441478
kind := g.table.type_kind(value.typ)
442479
if kind == .function {
443480
info := value.sym.info as ast.FnType
444481
sig := g.fn_var_signature(info.func.return_type, info.func.params.map(it.typ),
445482
'v')
446-
fn_builder.writeln('\t\t${sig} = *(voidptr*)map_get(&a, k, &(voidptr[]){ 0 });')
483+
fn_builder.writeln('\t\t${sig} = *(voidptr*)map_get(${a}, k, &(voidptr[]){ 0 });')
447484
} else {
448-
fn_builder.writeln('\t\t${ptr_value_styp} v = *(${ptr_value_styp}*)map_get(&a, k, &(${ptr_value_styp}[]){ 0 });')
485+
fn_builder.writeln('\t\t${ptr_value_styp} v = *(${ptr_value_styp}*)map_get(${a}, k, &(${ptr_value_styp}[]){ 0 });')
449486
}
450487
match kind {
451488
.string {
452-
fn_builder.writeln('\t\tif (!fast_string_eq(*(string*)map_get(&b, k, &(string[]){_SLIT("")}), v)) {')
489+
fn_builder.writeln('\t\tif (!fast_string_eq(*(string*)map_get(${b}, k, &(string[]){_SLIT("")}), v)) {')
453490
}
454491
.sum_type {
455492
eq_fn := g.gen_sumtype_equality_fn(value.typ)
456-
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
493+
fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
457494
}
458495
.struct_ {
459496
eq_fn := g.gen_struct_equality_fn(value.typ)
460-
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
497+
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
461498
}
462499
.interface_ {
463500
eq_fn := g.gen_interface_equality_fn(value.typ)
464-
fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
501+
fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
465502
}
466503
.array {
467504
eq_fn := g.gen_array_equality_fn(value.typ)
468-
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
505+
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
469506
}
470507
.array_fixed {
471508
eq_fn := g.gen_fixed_array_equality_fn(value.typ)
472-
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
509+
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
473510
}
474511
.map {
475512
eq_fn := g.gen_map_equality_fn(value.typ)
476-
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
513+
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
477514
}
478515
.alias {
479516
eq_fn := g.gen_alias_equality_fn(value.typ)
480-
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
517+
fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
481518
}
482519
.function {
483-
fn_builder.writeln('\t\tif (*(voidptr*)map_get(&b, k, &(voidptr[]){ 0 }) != v) {')
520+
fn_builder.writeln('\t\tif (*(voidptr*)map_get(${b}, k, &(voidptr[]){ 0 }) != v) {')
484521
}
485522
else {
486523
if value.typ.has_flag(.option) {
487-
fn_builder.writeln('\t\tif (memcmp(v.data, ((${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }))->data, sizeof(${g.base_type(value.typ)})) != 0) {')
524+
fn_builder.writeln('\t\tif (memcmp(v.data, ((${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }))->data, sizeof(${g.base_type(value.typ)})) != 0) {')
488525
} else {
489-
fn_builder.writeln('\t\tif (*(${ptr_value_styp}*)map_get(&b, k, &(${ptr_value_styp}[]){ 0 }) != v) {')
526+
fn_builder.writeln('\t\tif (*(${ptr_value_styp}*)map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }) != v) {')
490527
}
491528
}
492529
}

vlib/v/gen/c/cgen.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,8 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) bool {
18191819
g.expr(stmt.expr)
18201820
g.writeln(';')
18211821
} else {
1822-
ret_typ := if g.inside_assign {
1822+
// on assignemnt or struct field initialization
1823+
ret_typ := if g.inside_struct_init || g.inside_assign {
18231824
stmt.typ
18241825
} else {
18251826
g.fn_decl.return_type.clear_flag(.option)

vlib/v/tests/option_if_option_test.v

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import maps
2+
import x.json2
3+
4+
pub type Locale = string
5+
6+
pub struct ApplicationCommandOptionChoice {
7+
pub:
8+
name string
9+
name_localizations ?map[Locale]string
10+
}
11+
12+
pub fn ApplicationCommandOptionChoice.parse(j json2.Any) !ApplicationCommandOptionChoice {
13+
match j {
14+
map[string]json2.Any {
15+
return ApplicationCommandOptionChoice{
16+
name: j['name']! as string
17+
name_localizations: if m := j['name_localizations'] {
18+
maps.to_map[string, json2.Any, Locale, string](m as map[string]json2.Any,
19+
fn (k string, v json2.Any) (Locale, string) {
20+
return k, v as string
21+
})
22+
} else {
23+
none
24+
}
25+
}
26+
}
27+
else {
28+
return error('expected application command option choice to be object, got ${j.type_name()}')
29+
}
30+
}
31+
}
32+
33+
fn test_main() {
34+
var := ApplicationCommandOptionChoice.parse({
35+
'name': json2.Any('foo')
36+
'name_localizations': {
37+
'name': json2.Any('foo')
38+
}
39+
})!
40+
assert dump(var) == var
41+
}

0 commit comments

Comments
 (0)