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()
|
||||
as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast)
|
||||
obf_table map[string]string
|
||||
referenced_fns shared map[string]bool // functions that have been referenced
|
||||
nr_closures int
|
||||
expected_cast_type ast.Type // for match expr of sumtypes
|
||||
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
|
||||
done_optionals: global_g.done_optionals
|
||||
is_autofree: global_g.pref.autofree
|
||||
referenced_fns: global_g.referenced_fns
|
||||
}
|
||||
g.gen_file()
|
||||
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' }
|
||||
else { got_styp }
|
||||
}
|
||||
exp_styp := exp_sym.cname
|
||||
mut fname := '/*$exp_sym*/I_${got_styp}_to_Interface_$exp_styp'
|
||||
got_is_shared := got_type.has_flag(.shared_f)
|
||||
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 {
|
||||
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()
|
||||
}
|
||||
|
||||
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
|
||||
fn (mut g Gen) interface_table() string {
|
||||
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) {
|
||||
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 {
|
||||
@ -6685,7 +6724,13 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
||||
typ: st.set_nr_muls(1)
|
||||
}
|
||||
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.write_string('\t')
|
||||
if method.return_type != ast.void_type {
|
||||
@ -6704,7 +6749,11 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
||||
}
|
||||
methods_wrapper.writeln('${fargs[1..].join(', ')});')
|
||||
} else {
|
||||
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
||||
if parameter_name.starts_with('__shared__') {
|
||||
methods_wrapper.writeln('${method_call}(${fargs.join(', ')}->val);')
|
||||
} else {
|
||||
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
||||
}
|
||||
}
|
||||
methods_wrapper.writeln('}')
|
||||
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
||||
|
@ -725,9 +725,17 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
$if debug_interface_method_call ? {
|
||||
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.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)
|
||||
g.write('${dot}_typ]._method_${mname}(')
|
||||
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