cgen: fix interface struct field initialization (#7340)
parent
7426544610
commit
604eab7742
|
@ -566,10 +566,13 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
|||
}
|
||||
}
|
||||
inited_fields << field_name
|
||||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||
c.expected_type = info_field.typ
|
||||
expr_type := c.expr(field.expr)
|
||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||
if expr_type != table.void_type && expr_type_sym.kind != .placeholder {
|
||||
if field_type_sym.kind == .interface_ {
|
||||
c.type_implements(expr_type, info_field.typ, field.pos)
|
||||
} else if expr_type != table.void_type && expr_type_sym.kind != .placeholder {
|
||||
c.check_expected(expr_type, info_field.typ) or {
|
||||
c.error('cannot assign to field `$info_field.name`: $err', field.pos)
|
||||
}
|
||||
|
@ -2263,7 +2266,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
else {}
|
||||
}
|
||||
if !is_blank_ident && right_sym.kind != .placeholder {
|
||||
if !is_blank_ident && right_sym.kind != .placeholder && left_sym.kind != .interface_ {
|
||||
// Dual sides check (compatibility check)
|
||||
c.check_expected(right_type_unwrapped, left_type_unwrapped) or {
|
||||
c.error('cannot assign to `$left`: $err', right.position())
|
||||
|
|
|
@ -1734,6 +1734,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
// `a := 1` | `a,b := 1,2`
|
||||
for i, left in assign_stmt.left {
|
||||
mut is_interface := false
|
||||
mut var_type := assign_stmt.left_types[i]
|
||||
mut val_type := assign_stmt.right_types[i]
|
||||
val := assign_stmt.right[i]
|
||||
|
@ -1742,6 +1743,19 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
mut ident := ast.Ident{
|
||||
scope: 0
|
||||
}
|
||||
left_sym := g.table.get_type_symbol(var_type)
|
||||
if left_sym.kind == .interface_ {
|
||||
if left is ast.SelectorExpr {
|
||||
ident = left.root_ident()
|
||||
if ident.obj is ast.Var {
|
||||
idobj := ident.obj as ast.Var
|
||||
root_type_sym := g.table.get_type_symbol(idobj.typ)
|
||||
if root_type_sym.kind == .struct_ {
|
||||
is_interface = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if left is ast.Ident {
|
||||
ident = left
|
||||
// id_info := ident.var_info()
|
||||
|
@ -1799,6 +1813,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
right_sym := g.table.get_type_symbol(val_type)
|
||||
g.is_assign_lhs = true
|
||||
if is_interface && right_sym.kind == .interface_ {
|
||||
is_interface = false
|
||||
}
|
||||
if val_type.has_flag(.optional) {
|
||||
g.right_is_opt = true
|
||||
}
|
||||
|
@ -1939,7 +1956,13 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
if assign_stmt.has_cross_var {
|
||||
g.gen_cross_tmp_variable(assign_stmt.left, val)
|
||||
} else {
|
||||
if is_interface {
|
||||
g.interface_call(val_type, var_type)
|
||||
}
|
||||
g.expr_with_cast(val, val_type, var_type)
|
||||
if is_interface {
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4340,8 +4363,11 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
continue
|
||||
}
|
||||
g.write('.$field_name = ')
|
||||
expected_field_type_sym := g.table.get_type_symbol(sfield.expected_type)
|
||||
field_type_sym := g.table.get_type_symbol(sfield.typ)
|
||||
mut cloned := false
|
||||
is_interface := expected_field_type_sym.kind == .interface_ &&
|
||||
field_type_sym.kind != .interface_
|
||||
if g.autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
g.write('/*clone1*/')
|
||||
if g.gen_clone_assignment(sfield.expr, field_type_sym, false) {
|
||||
|
@ -4349,11 +4375,17 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
}
|
||||
}
|
||||
if !cloned {
|
||||
if is_interface {
|
||||
g.interface_call(sfield.typ, sfield.expected_type)
|
||||
}
|
||||
if sfield.expected_type.is_ptr() && !(sfield.typ.is_ptr() || sfield.typ.is_pointer()) &&
|
||||
!sfield.typ.is_number() {
|
||||
g.write('/* autoref */&')
|
||||
}
|
||||
g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type)
|
||||
if is_interface {
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
if is_multiline {
|
||||
g.writeln(',')
|
||||
|
@ -5706,6 +5738,8 @@ fn (mut g Gen) interface_table() string {
|
|||
already_generated_mwrappers[interface_index_name] = current_iinidx
|
||||
current_iinidx++
|
||||
// eprintln('>>> current_iinidx: ${current_iinidx-iinidx_minimum_base} | interface_index_name: $interface_index_name')
|
||||
sb.writeln('_Interface I_${cctype}_to_Interface_${interface_name}($cctype* x);')
|
||||
sb.writeln('_Interface* I_${cctype}_to_Interface_${interface_name}_ptr($cctype* x);')
|
||||
cast_functions.writeln('
|
||||
_Interface I_${cctype}_to_Interface_${interface_name}($cctype* x) {
|
||||
return (_Interface) {
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
interface Speaker {
|
||||
say_hello() string
|
||||
speak(msg string)
|
||||
}
|
||||
|
||||
struct Boss {
|
||||
name string
|
||||
}
|
||||
|
||||
fn (b Boss) say_hello() string {
|
||||
return "Hello, My name is $b.name and I\'m the bawz"
|
||||
}
|
||||
|
||||
fn (b Boss) speak(msg string) {
|
||||
println(msg)
|
||||
}
|
||||
|
||||
struct Cat {
|
||||
name string
|
||||
breed string
|
||||
}
|
||||
|
||||
fn (c Cat) say_hello() string {
|
||||
return 'Meow meow $c.name the $c.breed meow'
|
||||
}
|
||||
|
||||
fn (c Cat) speak(msg string) {
|
||||
println('Meow $msg')
|
||||
}
|
||||
|
||||
struct Baz {
|
||||
mut:
|
||||
sp Speaker
|
||||
}
|
||||
|
||||
fn test_interface_struct() {
|
||||
bz1 := Baz{
|
||||
sp: Boss{
|
||||
name: 'Richard'
|
||||
}
|
||||
}
|
||||
assert bz1.sp.say_hello() == "Hello, My name is Richard and I\'m the bawz"
|
||||
print('Test Boss inside Baz struct: ')
|
||||
bz1.sp.speak('Hello world!')
|
||||
bz2 := Baz{
|
||||
sp: Cat{
|
||||
name: 'Grungy'
|
||||
breed: 'Persian Cat'
|
||||
}
|
||||
}
|
||||
assert bz2.sp.say_hello() == 'Meow meow Grungy the Persian Cat meow'
|
||||
print('Test Cat inside Baz struct: ')
|
||||
bz2.sp.speak('Hello world!')
|
||||
}
|
||||
|
||||
fn test_interface_mut_struct() {
|
||||
mut mbaz := Baz{
|
||||
sp: Boss{
|
||||
name: 'Derek'
|
||||
}
|
||||
}
|
||||
assert mbaz.sp.say_hello() == "Hello, My name is Derek and I\'m the bawz"
|
||||
mbaz.sp = Cat{
|
||||
name: 'Dog'
|
||||
breed: 'Not a dog'
|
||||
}
|
||||
assert mbaz.sp.say_hello() == 'Meow meow Dog the Not a dog meow'
|
||||
}
|
||||
|
||||
fn test_interface_struct_from_array() {
|
||||
bazs := [
|
||||
Baz{
|
||||
sp: Cat{
|
||||
name: 'Kitty'
|
||||
breed: 'Catty Koo'
|
||||
}
|
||||
},
|
||||
Baz{
|
||||
sp: Boss{
|
||||
name: 'Bob'
|
||||
}
|
||||
},
|
||||
]
|
||||
assert bazs[0].sp.say_hello() == 'Meow meow Kitty the Catty Koo meow'
|
||||
assert bazs[1].sp.say_hello() == "Hello, My name is Bob and I\'m the bawz"
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: fix this too; currently with V 0.1.30 7426544 produces: `V panic: as cast: cannot cast 200 to 197`
|
||||
fn test_interface_struct_from_mut_array() {
|
||||
mut bazs := [
|
||||
Baz{
|
||||
sp: Cat{
|
||||
name: 'Kitty'
|
||||
breed: 'Catty Koo'
|
||||
}
|
||||
},
|
||||
Baz{
|
||||
sp: Boss{
|
||||
name: 'Bob'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
bazs[0].sp = Boss{
|
||||
name: 'Ross'
|
||||
}
|
||||
|
||||
bazs[1].sp = Cat{
|
||||
name: 'Doggy'
|
||||
breed: 'Doggy Doo'
|
||||
}
|
||||
|
||||
assert bazs[0].sp.say_hello() == 'Hello, My name is Ross and I\'m the bawz'
|
||||
assert bazs[1].sp.say_hello() == 'Meow meow Doggy the Doggy Doo meow'
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue