mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix compile error on locking interface value (#12883)
This commit is contained in:
parent
c26e040d33
commit
35418b8413
@ -183,6 +183,7 @@ mut:
|
|||||||
force_main_console bool // true when [console] used on fn main()
|
force_main_console bool // true when [console] used on fn main()
|
||||||
as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast)
|
as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast)
|
||||||
obf_table map[string]string
|
obf_table map[string]string
|
||||||
|
referenced_fns shared map[string]bool // functions that have been referenced
|
||||||
nr_closures int
|
nr_closures int
|
||||||
expected_cast_type ast.Type // for match expr of sumtypes
|
expected_cast_type ast.Type // for match expr of sumtypes
|
||||||
anon_fn bool
|
anon_fn bool
|
||||||
@ -523,6 +524,7 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
|
|||||||
threaded_fns: global_g.threaded_fns
|
threaded_fns: global_g.threaded_fns
|
||||||
done_optionals: global_g.done_optionals
|
done_optionals: global_g.done_optionals
|
||||||
is_autofree: global_g.pref.autofree
|
is_autofree: global_g.pref.autofree
|
||||||
|
referenced_fns: global_g.referenced_fns
|
||||||
}
|
}
|
||||||
g.gen_file()
|
g.gen_file()
|
||||||
return g
|
return g
|
||||||
@ -2353,8 +2355,18 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
|||||||
'f64' { 'float_literal' }
|
'f64' { 'float_literal' }
|
||||||
else { got_styp }
|
else { got_styp }
|
||||||
}
|
}
|
||||||
exp_styp := exp_sym.cname
|
got_is_shared := got_type.has_flag(.shared_f)
|
||||||
mut fname := '/*$exp_sym*/I_${got_styp}_to_Interface_$exp_styp'
|
exp_styp := if got_is_shared { '__shared__$exp_sym.cname' } else { exp_sym.cname }
|
||||||
|
// If it's shared, we need to use the other caster:
|
||||||
|
mut fname := if got_is_shared {
|
||||||
|
'I___shared__${got_styp}_to_shared_Interface_$exp_styp'
|
||||||
|
} else {
|
||||||
|
'I_${got_styp}_to_Interface_$exp_styp'
|
||||||
|
}
|
||||||
|
lock g.referenced_fns {
|
||||||
|
g.referenced_fns[fname] = true
|
||||||
|
}
|
||||||
|
fname = '/*$exp_sym*/$fname'
|
||||||
if exp_sym.info.is_generic {
|
if exp_sym.info.is_generic {
|
||||||
fname = g.generic_fn_name(exp_sym.info.concrete_types, fname, false)
|
fname = g.generic_fn_name(exp_sym.info.concrete_types, fname, false)
|
||||||
}
|
}
|
||||||
@ -6497,6 +6509,14 @@ fn (g Gen) as_cast_name_table() string {
|
|||||||
return name_ast.str()
|
return name_ast.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (g Gen) has_been_referenced(fn_name string) bool {
|
||||||
|
mut referenced := false
|
||||||
|
lock g.referenced_fns {
|
||||||
|
referenced = g.referenced_fns[fn_name]
|
||||||
|
}
|
||||||
|
return referenced
|
||||||
|
}
|
||||||
|
|
||||||
// Generates interface table and interface indexes
|
// Generates interface table and interface indexes
|
||||||
fn (mut g Gen) interface_table() string {
|
fn (mut g Gen) interface_table() string {
|
||||||
mut sb := strings.new_builder(100)
|
mut sb := strings.new_builder(100)
|
||||||
@ -6607,6 +6627,25 @@ fn (mut g Gen) interface_table() string {
|
|||||||
static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype* x) {
|
static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype* x) {
|
||||||
return $cast_struct_str;
|
return $cast_struct_str;
|
||||||
}')
|
}')
|
||||||
|
|
||||||
|
shared_fn_name := 'I___shared__${cctype}_to_shared_Interface___shared__$interface_name'
|
||||||
|
// Avoid undefined types errors by only generating the converters that are referenced:
|
||||||
|
if g.has_been_referenced(shared_fn_name) {
|
||||||
|
mut cast_shared_struct := strings.new_builder(100)
|
||||||
|
cast_shared_struct.writeln('(__shared__$interface_name) {')
|
||||||
|
cast_shared_struct.writeln('\t\t.mtx = {0},')
|
||||||
|
cast_shared_struct.writeln('\t\t.val = {')
|
||||||
|
cast_shared_struct.writeln('\t\t\t._$cctype = &x->val,')
|
||||||
|
cast_shared_struct.writeln('\t\t\t._typ = $interface_index_name,')
|
||||||
|
cast_shared_struct.writeln('\t\t}')
|
||||||
|
cast_shared_struct.write_string('\t}')
|
||||||
|
cast_shared_struct_str := cast_shared_struct.str()
|
||||||
|
cast_functions.writeln('
|
||||||
|
// Casting functions for converting "__shared__$cctype" to interface "__shared__$interface_name"
|
||||||
|
static inline __shared__$interface_name ${shared_fn_name}(__shared__$cctype* x) {
|
||||||
|
return $cast_shared_struct_str;
|
||||||
|
}')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.pref.build_mode != .build_module {
|
if g.pref.build_mode != .build_module {
|
||||||
@ -6685,7 +6724,13 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
|||||||
typ: st.set_nr_muls(1)
|
typ: st.set_nr_muls(1)
|
||||||
}
|
}
|
||||||
fargs, _, _ := g.fn_args(params, voidptr(0))
|
fargs, _, _ := g.fn_args(params, voidptr(0))
|
||||||
methods_wrapper.write_string(g.out.cut_last(g.out.len - params_start_pos))
|
mut parameter_name := g.out.cut_last(g.out.len - params_start_pos)
|
||||||
|
|
||||||
|
if st.is_ptr() {
|
||||||
|
parameter_name = parameter_name.trim_left('__shared__')
|
||||||
|
}
|
||||||
|
|
||||||
|
methods_wrapper.write_string(parameter_name)
|
||||||
methods_wrapper.writeln(') {')
|
methods_wrapper.writeln(') {')
|
||||||
methods_wrapper.write_string('\t')
|
methods_wrapper.write_string('\t')
|
||||||
if method.return_type != ast.void_type {
|
if method.return_type != ast.void_type {
|
||||||
@ -6703,9 +6748,13 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
|||||||
methods_wrapper.write_string('->$esym.embed_name()')
|
methods_wrapper.write_string('->$esym.embed_name()')
|
||||||
}
|
}
|
||||||
methods_wrapper.writeln('${fargs[1..].join(', ')});')
|
methods_wrapper.writeln('${fargs[1..].join(', ')});')
|
||||||
|
} else {
|
||||||
|
if parameter_name.starts_with('__shared__') {
|
||||||
|
methods_wrapper.writeln('${method_call}(${fargs.join(', ')}->val);')
|
||||||
} else {
|
} else {
|
||||||
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
methods_wrapper.writeln('}')
|
methods_wrapper.writeln('}')
|
||||||
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
||||||
method_call += iwpostfix
|
method_call += iwpostfix
|
||||||
|
@ -725,9 +725,17 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||||||
$if debug_interface_method_call ? {
|
$if debug_interface_method_call ? {
|
||||||
eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name | pos: $node.pos')
|
eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name | pos: $node.pos')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
left_is_shared := node.left_type.has_flag(.shared_f)
|
||||||
g.write('${c_name(receiver_type_name)}_name_table[')
|
g.write('${c_name(receiver_type_name)}_name_table[')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
dot := if left_is_shared {
|
||||||
|
'->val.'
|
||||||
|
} else if node.left_type.is_ptr() {
|
||||||
|
'->'
|
||||||
|
} else {
|
||||||
|
'.'
|
||||||
|
}
|
||||||
mname := c_name(node.name)
|
mname := c_name(node.name)
|
||||||
g.write('${dot}_typ]._method_${mname}(')
|
g.write('${dot}_typ]._method_${mname}(')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
|
81
vlib/v/tests/shared_interface_test.v
Normal file
81
vlib/v/tests/shared_interface_test.v
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
interface MyInterface {
|
||||||
|
foo() string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
pub mut:
|
||||||
|
fooer shared MyInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyImplementor {
|
||||||
|
num int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (m MyImplementor) foo() string {
|
||||||
|
// Can read member properties:
|
||||||
|
num := m.num
|
||||||
|
return 'Hello World $num!'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_shared_interface_lock_1() {
|
||||||
|
shared imp1 := MyImplementor{
|
||||||
|
num: 1
|
||||||
|
}
|
||||||
|
s1 := MyStruct{
|
||||||
|
fooer: imp1
|
||||||
|
}
|
||||||
|
lock s1.fooer {
|
||||||
|
assert s1.fooer.foo() == 'Hello World 1!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_shared_interface_lock_2() {
|
||||||
|
shared imp := MyOtherImplementor{
|
||||||
|
x: 1
|
||||||
|
y: 2
|
||||||
|
s: 'testing'
|
||||||
|
}
|
||||||
|
s := MyStruct{
|
||||||
|
fooer: imp
|
||||||
|
}
|
||||||
|
|
||||||
|
lock s.fooer {
|
||||||
|
assert s.fooer.foo() == 'Hello World (1, 2, testing)!'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock is released and can be locked again:
|
||||||
|
lock s.fooer {
|
||||||
|
assert s.fooer.foo() == 'Hello World (1, 2, testing)!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Fix modifying shared interface value
|
||||||
|
// fn test_shared_interface_can_be_modified() {
|
||||||
|
// shared imp1 := MyImplementor{num: 6}
|
||||||
|
// shared imp2 := MyOtherImplementor{
|
||||||
|
// x: 7
|
||||||
|
// y: 3
|
||||||
|
// s: 'here be dragons...'
|
||||||
|
// }
|
||||||
|
// s := MyStruct{
|
||||||
|
// fooer: imp1
|
||||||
|
// }
|
||||||
|
// lock s.fooer {
|
||||||
|
// assert(s.fooer.foo() == 'Hello World 6!')
|
||||||
|
// s.fooer = imp2
|
||||||
|
// }
|
||||||
|
// lock s.fooer {
|
||||||
|
// assert(s.fooer.foo() == 'Hello World (7, 3, here be dragons...)!')
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
struct MyOtherImplementor {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (m MyOtherImplementor) foo() string {
|
||||||
|
// Different implementation:
|
||||||
|
return 'Hello World ($m.x, $m.y, $m.s)!'
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user