mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
ast, cgen: fix wrong name and cname, when array and fixed array elements have optional (fix #16099) (#16122)
This commit is contained in:
parent
2083e6b04c
commit
07310d850d
@ -884,21 +884,22 @@ pub fn (t &Table) known_type_idx(typ Type) bool {
|
||||
pub fn (t &Table) array_name(elem_type Type) string {
|
||||
elem_type_sym := t.sym(elem_type)
|
||||
ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
|
||||
return '[]$ptr$elem_type_sym.name'
|
||||
opt := if elem_type.has_flag(.optional) { '?' } else { '' }
|
||||
res := if elem_type.has_flag(.result) { '!' } else { '' }
|
||||
return '[]$opt$res$ptr$elem_type_sym.name'
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) array_cname(elem_type Type) string {
|
||||
elem_type_sym := t.sym(elem_type)
|
||||
mut res := ''
|
||||
if elem_type.is_ptr() {
|
||||
res = '_ptr'.repeat(elem_type.nr_muls())
|
||||
}
|
||||
suffix := if elem_type.is_ptr() { '_ptr'.repeat(elem_type.nr_muls()) } else { '' }
|
||||
opt := if elem_type.has_flag(.optional) { '_option_' } else { '' }
|
||||
res := if elem_type.has_flag(.result) { '_result_' } else { '' }
|
||||
if elem_type_sym.cname.contains('<') {
|
||||
type_name := elem_type_sym.cname.replace_each(['<', '_T_', ', ', '_', '>', ''])
|
||||
return 'Array_$type_name' + res
|
||||
return 'Array_$opt$res$type_name$suffix'
|
||||
} else {
|
||||
return 'Array_$elem_type_sym.cname' + res
|
||||
return 'Array_$opt$res$elem_type_sym.cname$suffix'
|
||||
}
|
||||
}
|
||||
|
||||
@ -908,22 +909,28 @@ pub fn (t &Table) array_cname(elem_type Type) string {
|
||||
pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) string {
|
||||
elem_type_sym := t.sym(elem_type)
|
||||
ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
|
||||
opt := if elem_type.has_flag(.optional) { '?' } else { '' }
|
||||
res := if elem_type.has_flag(.result) { '!' } else { '' }
|
||||
size_str := if size_expr is EmptyExpr || size != 987654321 {
|
||||
size.str()
|
||||
} else {
|
||||
size_expr.str()
|
||||
}
|
||||
return '[$size_str]$ptr$elem_type_sym.name'
|
||||
return '[$size_str]$opt$res$ptr$elem_type_sym.name'
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) array_fixed_cname(elem_type Type, size int) string {
|
||||
elem_type_sym := t.sym(elem_type)
|
||||
mut res := ''
|
||||
if elem_type.is_ptr() {
|
||||
res = '_ptr$elem_type.nr_muls()'
|
||||
suffix := if elem_type.is_ptr() { '_ptr$elem_type.nr_muls()' } else { '' }
|
||||
opt := if elem_type.has_flag(.optional) { '_option_' } else { '' }
|
||||
res := if elem_type.has_flag(.result) { '_result_' } else { '' }
|
||||
if elem_type_sym.cname.contains('<') {
|
||||
type_name := elem_type_sym.cname.replace_each(['<', '_T_', ', ', '_', '>', ''])
|
||||
return 'Array_fixed_$opt$res$type_name${suffix}_$size'
|
||||
} else {
|
||||
return 'Array_fixed_$opt$res$elem_type_sym.cname${suffix}_$size'
|
||||
}
|
||||
return 'Array_fixed_$elem_type_sym.cname${res}_$size'
|
||||
}
|
||||
|
||||
[inline]
|
||||
@ -1012,7 +1019,7 @@ pub fn (t &Table) thread_cname(return_type Type) string {
|
||||
pub fn (t &Table) map_name(key_type Type, value_type Type) string {
|
||||
key_type_sym := t.sym(key_type)
|
||||
value_type_sym := t.sym(value_type)
|
||||
ptr := if value_type.is_ptr() { '&' } else { '' }
|
||||
ptr := if value_type.is_ptr() { '&'.repeat(value_type.nr_muls()) } else { '' }
|
||||
opt := if value_type.has_flag(.optional) { '?' } else { '' }
|
||||
res := if value_type.has_flag(.result) { '!' } else { '' }
|
||||
return 'map[$key_type_sym.name]$opt$res$ptr$value_type_sym.name'
|
||||
@ -1022,11 +1029,16 @@ pub fn (t &Table) map_name(key_type Type, value_type Type) string {
|
||||
pub fn (t &Table) map_cname(key_type Type, value_type Type) string {
|
||||
key_type_sym := t.sym(key_type)
|
||||
value_type_sym := t.sym(value_type)
|
||||
suffix := if value_type.is_ptr() { '_ptr' } else { '' }
|
||||
suffix := if value_type.is_ptr() { '_ptr'.repeat(value_type.nr_muls()) } else { '' }
|
||||
opt := if value_type.has_flag(.optional) { '_option_' } else { '' }
|
||||
res := if value_type.has_flag(.result) { '_result_' } else { '' }
|
||||
if value_type_sym.cname.contains('<') {
|
||||
type_name := value_type_sym.cname.replace_each(['<', '_T_', ', ', '_', '>', ''])
|
||||
return 'Map_${key_type_sym.cname}_$opt$res$type_name$suffix'
|
||||
} else {
|
||||
return 'Map_${key_type_sym.cname}_$opt$res$value_type_sym.cname$suffix'
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut t Table) find_or_register_chan(elem_type Type, is_mut bool) int {
|
||||
name := t.chan_name(elem_type, is_mut)
|
||||
|
@ -72,7 +72,9 @@ mut:
|
||||
embedded_data strings.Builder // data to embed in the executable/binary
|
||||
shared_types strings.Builder // shared/lock types
|
||||
shared_functions strings.Builder // shared constructors
|
||||
options strings.Builder // `option_xxxx` types
|
||||
out_options_forward strings.Builder // forward `option_xxxx` types
|
||||
out_options strings.Builder // `option_xxxx` types
|
||||
out_results_forward strings.Builder // forward`result_xxxx` types
|
||||
out_results strings.Builder // `result_xxxx` types
|
||||
json_forward_decls strings.Builder // json type forward decls
|
||||
sql_buf strings.Builder // for writing exprs to args via `sqlite3_bind_int()` etc
|
||||
@ -101,7 +103,10 @@ mut:
|
||||
is_fn_index_call bool
|
||||
is_cc_msvc bool // g.pref.ccompiler == 'msvc'
|
||||
vlines_path string // set to the proper path for generating #line directives
|
||||
optionals_pos_forward int // insertion point to forward
|
||||
options_forward []string // to forward
|
||||
optionals map[string]string // to avoid duplicates
|
||||
results_forward []string // to forward
|
||||
results map[string]string // to avoid duplicates
|
||||
done_optionals shared []string // to avoid duplicates
|
||||
chan_pop_optionals map[string]string // types for `x := <-ch or {...}`
|
||||
@ -270,7 +275,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string,
|
||||
dump_funcs: strings.new_builder(100)
|
||||
pcs_declarations: strings.new_builder(100)
|
||||
embedded_data: strings.new_builder(1000)
|
||||
options: strings.new_builder(100)
|
||||
out_options_forward: strings.new_builder(100)
|
||||
out_options: strings.new_builder(100)
|
||||
out_results_forward: strings.new_builder(100)
|
||||
out_results: strings.new_builder(100)
|
||||
shared_types: strings.new_builder(100)
|
||||
shared_functions: strings.new_builder(100)
|
||||
@ -456,6 +463,22 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string,
|
||||
g.write_init_function()
|
||||
}
|
||||
|
||||
// insert for optionals forward
|
||||
if g.out_options_forward.len > 0 || g.out_results_forward.len > 0 {
|
||||
tail := g.type_definitions.cut_to(g.optionals_pos_forward)
|
||||
if g.out_options_forward.len > 0 {
|
||||
g.type_definitions.writeln('// #start V forward option_xxx definitions:')
|
||||
g.type_definitions.writeln(g.out_options_forward.str())
|
||||
g.type_definitions.writeln('// #end V forward option_xxx definitions\n')
|
||||
}
|
||||
if g.out_results_forward.len > 0 {
|
||||
g.type_definitions.writeln('// #start V forward result_xxx definitions:')
|
||||
g.type_definitions.writeln(g.out_results_forward.str())
|
||||
g.type_definitions.writeln('// #end V forward result_xxx definitions\n')
|
||||
}
|
||||
g.type_definitions.writeln(tail)
|
||||
}
|
||||
|
||||
g.finish()
|
||||
|
||||
mut b := strings.new_builder(640000)
|
||||
@ -488,7 +511,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string,
|
||||
b.writeln('\n// V shared types:')
|
||||
b.write_string(g.shared_types.str())
|
||||
b.writeln('\n// V Option_xxx definitions:')
|
||||
b.write_string(g.options.str())
|
||||
b.write_string(g.out_options.str())
|
||||
b.writeln('\n// V result_xxx definitions:')
|
||||
b.write_string(g.out_results.str())
|
||||
b.writeln('\n// V json forward decls:')
|
||||
@ -591,7 +614,9 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
|
||||
pcs_declarations: strings.new_builder(100)
|
||||
hotcode_definitions: strings.new_builder(100)
|
||||
embedded_data: strings.new_builder(1000)
|
||||
options: strings.new_builder(100)
|
||||
out_options_forward: strings.new_builder(100)
|
||||
out_options: strings.new_builder(100)
|
||||
out_results_forward: strings.new_builder(100)
|
||||
out_results: strings.new_builder(100)
|
||||
shared_types: strings.new_builder(100)
|
||||
shared_functions: strings.new_builder(100)
|
||||
@ -615,6 +640,8 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
|
||||
array_sort_fn: global_g.array_sort_fn
|
||||
waiter_fns: global_g.waiter_fns
|
||||
threaded_fns: global_g.threaded_fns
|
||||
options_forward: global_g.options_forward
|
||||
results_forward: global_g.results_forward
|
||||
done_optionals: global_g.done_optionals
|
||||
is_autofree: global_g.pref.autofree
|
||||
referenced_fns: global_g.referenced_fns
|
||||
@ -650,7 +677,9 @@ pub fn (mut g Gen) free_builders() {
|
||||
g.shared_functions.free()
|
||||
g.channel_definitions.free()
|
||||
g.thread_definitions.free()
|
||||
g.options.free()
|
||||
g.out_options_forward.free()
|
||||
g.out_options.free()
|
||||
g.out_results_forward.free()
|
||||
g.out_results.free()
|
||||
g.json_forward_decls.free()
|
||||
g.enum_typedefs.free()
|
||||
@ -734,6 +763,7 @@ pub fn (mut g Gen) init() {
|
||||
g.cheaders.writeln('#include <spawn.h>')
|
||||
}
|
||||
g.write_builtin_types()
|
||||
g.optionals_pos_forward = g.type_definitions.len
|
||||
g.write_typedef_types()
|
||||
g.write_typeof_functions()
|
||||
g.write_sorted_types()
|
||||
@ -1086,7 +1116,11 @@ fn (mut g Gen) write_optionals() {
|
||||
}
|
||||
done << base
|
||||
g.typedefs.writeln('typedef struct $styp $styp;')
|
||||
g.options.write_string(g.optional_type_text(styp, base) + ';\n\n')
|
||||
if base in g.options_forward {
|
||||
g.out_options_forward.write_string(g.optional_type_text(styp, base) + ';\n\n')
|
||||
} else {
|
||||
g.out_options.write_string(g.optional_type_text(styp, base) + ';\n\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1098,8 +1132,12 @@ fn (mut g Gen) write_results() {
|
||||
}
|
||||
done << base
|
||||
g.typedefs.writeln('typedef struct $styp $styp;')
|
||||
if base in g.results_forward {
|
||||
g.out_results_forward.write_string(g.result_type_text(styp, base) + ';\n\n')
|
||||
} else {
|
||||
g.out_results.write_string(g.result_type_text(styp, base) + ';\n\n')
|
||||
}
|
||||
}
|
||||
for k, _ in g.table.anon_struct_names {
|
||||
ck := c_name(k)
|
||||
g.typedefs.writeln('typedef struct $ck $ck;')
|
||||
@ -1314,6 +1352,12 @@ pub fn (mut g Gen) write_typedef_types() {
|
||||
g.type_definitions.writeln(def_str)
|
||||
} else {
|
||||
g.type_definitions.writeln('typedef $fixed $styp [$len];')
|
||||
base := g.typ(info.elem_type.clear_flag(.optional).clear_flag(.result))
|
||||
if info.elem_type.has_flag(.optional) && base !in g.options_forward {
|
||||
g.options_forward << base
|
||||
} else if info.elem_type.has_flag(.result) && base !in g.results_forward {
|
||||
g.results_forward << base
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2272,7 +2316,8 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
||||
return
|
||||
}
|
||||
if got_sym.info !is ast.Interface && exp_sym.info is ast.Interface
|
||||
&& got_type.idx() != expected_type.idx() && !expected_type.has_flag(.optional) {
|
||||
&& got_type.idx() != expected_type.idx() && !expected_type.has_flag(.optional)
|
||||
&& !expected_type.has_flag(.result) {
|
||||
if expr is ast.StructInit && !got_type.is_ptr() {
|
||||
g.inside_cast_in_heap++
|
||||
got_styp := g.cc_type(got_type.ref(), true)
|
||||
@ -2362,7 +2407,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
||||
// Generic dereferencing logic
|
||||
neither_void := ast.voidptr_type !in [got_type, expected_type]
|
||||
if expected_type.has_flag(.shared_f) && !got_type_raw.has_flag(.shared_f)
|
||||
&& !expected_type.has_flag(.optional) {
|
||||
&& !expected_type.has_flag(.optional) && !expected_type.has_flag(.result) {
|
||||
shared_styp := exp_styp[0..exp_styp.len - 1] // `shared` implies ptr, so eat one `*`
|
||||
if got_type_raw.is_ptr() {
|
||||
g.error('cannot convert reference to `shared`', expr.pos())
|
||||
@ -2393,8 +2438,8 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
||||
got_deref_type := got_type.deref()
|
||||
deref_sym := g.table.sym(got_deref_type)
|
||||
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
|
||||
got_is_opt := got_type.has_flag(.optional)
|
||||
if deref_will_match || got_is_opt || expr.is_auto_deref_var() {
|
||||
got_is_opt_or_res := got_type.has_flag(.optional) || got_type.has_flag(.result)
|
||||
if deref_will_match || got_is_opt_or_res || expr.is_auto_deref_var() {
|
||||
g.write('*')
|
||||
}
|
||||
}
|
||||
@ -3452,8 +3497,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
}
|
||||
sym := g.table.sym(g.unwrap_generic(node.expr_type))
|
||||
// if node expr is a root ident and an optional
|
||||
mut is_optional := node.expr is ast.Ident && node.expr_type.has_flag(.optional)
|
||||
if is_optional {
|
||||
mut is_opt_or_res := node.expr is ast.Ident
|
||||
&& (node.expr_type.has_flag(.optional) || node.expr_type.has_flag(.result))
|
||||
if is_opt_or_res {
|
||||
opt_base_typ := g.base_type(node.expr_type)
|
||||
g.writeln('(*($opt_base_typ*)')
|
||||
}
|
||||
@ -3584,7 +3630,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
} else {
|
||||
g.expr(node.expr)
|
||||
}
|
||||
if is_optional {
|
||||
if is_opt_or_res {
|
||||
g.write('.data)')
|
||||
}
|
||||
// struct embedding
|
||||
|
44
vlib/v/tests/array_elements_with_optional_test.v
Normal file
44
vlib/v/tests/array_elements_with_optional_test.v
Normal file
@ -0,0 +1,44 @@
|
||||
struct Foo1 {
|
||||
arr1 [5]?int
|
||||
arr2 [5]int
|
||||
}
|
||||
|
||||
fn get_has_optional_fixed() ?int {
|
||||
foo := Foo1{}
|
||||
return foo.arr1[0]
|
||||
}
|
||||
|
||||
fn get_no_optional_fixed() int {
|
||||
foo := Foo1{}
|
||||
return foo.arr2[0]
|
||||
}
|
||||
|
||||
fn test_optional_fixed() ? {
|
||||
x := get_has_optional_fixed()?
|
||||
assert x == 0
|
||||
assert get_no_optional_fixed() == 0
|
||||
}
|
||||
|
||||
struct Foo2 {
|
||||
mut:
|
||||
arr1 []?int
|
||||
arr2 []int
|
||||
}
|
||||
|
||||
fn get_has_optional() ?int {
|
||||
mut foo := Foo2{}
|
||||
foo.arr1 << 0
|
||||
return foo.arr1[0]
|
||||
}
|
||||
|
||||
fn get_no_optional() int {
|
||||
mut foo := Foo2{}
|
||||
foo.arr2 << 0
|
||||
return foo.arr2[0]
|
||||
}
|
||||
|
||||
fn test_optional_non_fixed() ? {
|
||||
x := get_has_optional()?
|
||||
assert x == 0
|
||||
assert get_no_optional() == 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user