Skip to content

Commit 1601de1

Browse files
authored
v: fix anon struct option support (fix #23789) (fix #23824) (#23830)
1 parent 5f5e48e commit 1601de1

File tree

9 files changed

+63
-8
lines changed

9 files changed

+63
-8
lines changed

vlib/v/ast/ast.v

+1
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ pub:
431431
global_pos int = -1 // __global:
432432
module_pos int = -1 // module:
433433
is_union bool
434+
is_option bool
434435
attrs []Attr
435436
pre_comments []Comment
436437
end_comments []Comment

vlib/v/ast/str.v

+6-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,12 @@ fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_m
186186
f.write_string(param.name)
187187
param_sym := t.sym(param.typ)
188188
if param_sym.info is Struct && param_sym.info.is_anon {
189-
f.write_string(' struct {')
189+
if param.typ.has_flag(.option) {
190+
f.write_string(' ?')
191+
} else {
192+
f.write_string(' ')
193+
}
194+
f.write_string('struct {')
190195
for field in param_sym.info.fields {
191196
f.write_string(' ${field.name} ${t.type_to_str(field.typ)}')
192197
if field.has_default_expr {

vlib/v/fmt/struct.v

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) {
1010
if node.is_pub && !is_anon {
1111
f.write('pub ')
1212
}
13+
if node.is_option {
14+
f.write('?')
15+
}
1316
if node.is_union {
1417
f.write('union')
1518
} else {

vlib/v/gen/c/cgen.v

+1-1
Original file line numberDiff line numberDiff line change
@@ -6504,7 +6504,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
65046504
}
65056505
}
65066506
}
6507-
g.struct_decl(sym.info, name, false)
6507+
g.struct_decl(sym.info, name, false, false)
65086508
struct_names[name] = true
65096509
}
65106510
}

vlib/v/gen/c/struct.v

+6-5
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
7777
g.write(')')
7878
}
7979
}
80-
if is_anon {
80+
if is_anon && !node.typ.has_flag(.option) {
8181
if node.language == .v {
8282
g.write('(${styp})')
8383
}
@@ -541,7 +541,7 @@ fn (mut g Gen) zero_struct_field(field ast.StructField) bool {
541541
return true
542542
}
543543

544-
fn (mut g Gen) struct_decl(s ast.Struct, name string, is_anon bool) {
544+
fn (mut g Gen) struct_decl(s ast.Struct, name string, is_anon bool, is_option bool) {
545545
if s.is_generic {
546546
return
547547
}
@@ -585,10 +585,11 @@ fn (mut g Gen) struct_decl(s ast.Struct, name string, is_anon bool) {
585585
}
586586
}
587587
if is_anon {
588+
option_prefix := if is_option { '_option_' } else { '' }
588589
if s.is_shared {
589-
g.type_definitions.write_string('\t__shared__${name}* ')
590+
g.type_definitions.write_string('\t${option_prefix}__shared__${name}* ')
590591
} else {
591-
g.type_definitions.write_string('\t${name} ')
592+
g.type_definitions.write_string('\t${option_prefix}${name} ')
592593
}
593594
return
594595
} else if s.is_union {
@@ -671,7 +672,7 @@ fn (mut g Gen) struct_decl(s ast.Struct, name string, is_anon bool) {
671672
if field_sym.info.is_anon {
672673
field_is_anon = true
673674
// Recursively generate code for this anon struct (this is the field's type)
674-
g.struct_decl(field_sym.info, field_sym.cname, true)
675+
g.struct_decl(field_sym.info, field_sym.cname, true, field.typ.has_flag(.option))
675676
// Now the field's name
676677
g.type_definitions.writeln(' ${field_name}${size_suffix};')
677678
}

vlib/v/parser/parse_type.v

+5-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,11 @@ fn (mut p Parser) parse_type() ast.Type {
525525
if p.tok.kind == .key_struct {
526526
p.anon_struct_decl = p.struct_decl(true)
527527
// Find the registered anon struct type, it was registered above in `p.struct_decl()`
528-
return p.table.find_type_idx(p.anon_struct_decl.name)
528+
mut typ := p.table.find_type_idx(p.anon_struct_decl.name)
529+
if is_option {
530+
typ = ast.new_type(typ).set_flag(.option)
531+
}
532+
return typ
529533
}
530534

531535
language := p.parse_language()

vlib/v/parser/struct.v

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
1414
start_pos := p.tok.pos()
1515
mut is_pub := p.tok.kind == .key_pub
1616
mut is_shared := p.tok.kind == .key_shared
17+
is_option := is_anon && p.prev_tok.kind == .question
1718
if is_pub {
1819
p.next()
1920
}
@@ -436,6 +437,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
436437
module_pos: module_pos
437438
language: language
438439
is_union: is_union
440+
is_option: is_option
439441
attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes
440442
pre_comments: pre_comments
441443
end_comments: end_comments
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
struct Foo {
2+
a ?struct {
3+
name string
4+
}
5+
}
6+
7+
fn test_main() {
8+
t := Foo{}
9+
assert '${t}' == 'Foo{
10+
a: Option(none)
11+
}'
12+
13+
t2 := Foo{
14+
a: struct {
15+
name: 'foo'
16+
}
17+
}
18+
assert '${t2}' == "Foo{
19+
a: Option(struct {
20+
name: 'foo'
21+
})
22+
}"
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn opt(params ?struct { name string surname string }) {
2+
if params == none {
3+
assert '${params}' == 'Option(none)'
4+
}
5+
if params != none {
6+
assert '${params}' == "struct {
7+
name: 'foo'
8+
surname: 'bar'
9+
}"
10+
}
11+
}
12+
13+
fn test_main() {
14+
opt(none)
15+
opt(struct { name: 'foo', surname: 'bar' })
16+
}

0 commit comments

Comments
 (0)