checker, cgen: fix generic empty interface to multi struct (#14132)
parent
9b565bf765
commit
5dce091379
|
@ -296,7 +296,7 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
||||||
c.smartcast_if_conds(node.right, mut scope)
|
c.smartcast_if_conds(node.right, mut scope)
|
||||||
} else if node.op == .key_is {
|
} else if node.op == .key_is {
|
||||||
right_expr := node.right
|
right_expr := node.right
|
||||||
mut right_type := match right_expr {
|
right_type := match right_expr {
|
||||||
ast.TypeNode {
|
ast.TypeNode {
|
||||||
right_expr.typ
|
right_expr.typ
|
||||||
}
|
}
|
||||||
|
@ -308,11 +308,10 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
||||||
ast.Type(0)
|
ast.Type(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
right_type = c.unwrap_generic(right_type)
|
|
||||||
if right_type != ast.Type(0) {
|
if right_type != ast.Type(0) {
|
||||||
left_sym := c.table.sym(node.left_type)
|
left_sym := c.table.sym(node.left_type)
|
||||||
right_sym := c.table.sym(right_type)
|
right_sym := c.table.sym(right_type)
|
||||||
mut expr_type := c.unwrap_generic(c.expr(node.left))
|
mut expr_type := c.expr(node.left)
|
||||||
if left_sym.kind == .aggregate {
|
if left_sym.kind == .aggregate {
|
||||||
expr_type = (left_sym.info as ast.Aggregate).sum_type
|
expr_type = (left_sym.info as ast.Aggregate).sum_type
|
||||||
}
|
}
|
||||||
|
@ -322,7 +321,7 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if !c.check_types(right_type, expr_type) {
|
} else if !c.check_types(right_type, expr_type) && left_sym.kind != .sum_type {
|
||||||
expect_str := c.table.type_to_str(right_type)
|
expect_str := c.table.type_to_str(right_type)
|
||||||
expr_str := c.table.type_to_str(expr_type)
|
expr_str := c.table.type_to_str(expr_type)
|
||||||
c.error('cannot use type `$expect_str` as type `$expr_str`', node.pos)
|
c.error('cannot use type `$expect_str` as type `$expr_str`', node.pos)
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
mut got_types := []ast.Type{}
|
mut got_types := []ast.Type{}
|
||||||
mut expr_idxs := []int{}
|
mut expr_idxs := []int{}
|
||||||
for i, expr in node.exprs {
|
for i, expr in node.exprs {
|
||||||
typ := c.expr(expr)
|
mut typ := c.expr(expr)
|
||||||
if typ == ast.void_type {
|
if typ == ast.void_type {
|
||||||
c.error('`$expr` used as value', node.pos)
|
c.error('`$expr` used as value', node.pos)
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,13 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
expr_idxs << i
|
expr_idxs << i
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if expr is ast.Ident {
|
||||||
|
if expr.obj is ast.Var {
|
||||||
|
if expr.obj.smartcasts.len > 0 {
|
||||||
|
typ = c.unwrap_generic(expr.obj.smartcasts.last())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
got_types << typ
|
got_types << typ
|
||||||
expr_idxs << i
|
expr_idxs << i
|
||||||
}
|
}
|
||||||
|
|
|
@ -3286,7 +3286,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||||
if field_sym.kind == .sum_type {
|
if field_sym.kind == .sum_type {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
cast_sym := g.table.sym(typ)
|
cast_sym := g.table.sym(g.unwrap_generic(typ))
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
dot := if field.typ.is_ptr() { '->' } else { '.' }
|
dot := if field.typ.is_ptr() { '->' } else { '.' }
|
||||||
sum_type_deref_field += ')$dot'
|
sum_type_deref_field += ')$dot'
|
||||||
|
|
|
@ -941,7 +941,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
g.gen_expr_to_string(node.left, rec_type)
|
g.gen_expr_to_string(node.left, rec_type)
|
||||||
return
|
return
|
||||||
} else if node.left.obj.smartcasts.len > 0 {
|
} else if node.left.obj.smartcasts.len > 0 {
|
||||||
rec_type = node.left.obj.smartcasts.last()
|
rec_type = g.unwrap_generic(node.left.obj.smartcasts.last())
|
||||||
cast_sym := g.table.sym(rec_type)
|
cast_sym := g.table.sym(rec_type)
|
||||||
if cast_sym.info is ast.Aggregate {
|
if cast_sym.info is ast.Aggregate {
|
||||||
rec_type = cast_sym.info.types[g.aggregate_type_idx]
|
rec_type = cast_sym.info.types[g.aggregate_type_idx]
|
||||||
|
@ -1331,7 +1331,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
if expr.obj is ast.Var {
|
if expr.obj is ast.Var {
|
||||||
typ = expr.obj.typ
|
typ = expr.obj.typ
|
||||||
if expr.obj.smartcasts.len > 0 {
|
if expr.obj.smartcasts.len > 0 {
|
||||||
typ = expr.obj.smartcasts.last()
|
typ = g.unwrap_generic(expr.obj.smartcasts.last())
|
||||||
cast_sym := g.table.sym(typ)
|
cast_sym := g.table.sym(typ)
|
||||||
if cast_sym.info is ast.Aggregate {
|
if cast_sym.info is ast.Aggregate {
|
||||||
typ = cast_sym.info.types[g.aggregate_type_idx]
|
typ = cast_sym.info.types[g.aggregate_type_idx]
|
||||||
|
|
|
@ -156,7 +156,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) {
|
||||||
if g.comptime_var_type_map.len > 0 || g.comptime_for_method.len > 0 {
|
if g.comptime_var_type_map.len > 0 || g.comptime_for_method.len > 0 {
|
||||||
exp_typ = expr.obj.typ
|
exp_typ = expr.obj.typ
|
||||||
} else if expr.obj.smartcasts.len > 0 {
|
} else if expr.obj.smartcasts.len > 0 {
|
||||||
exp_typ = expr.obj.smartcasts.last()
|
exp_typ = g.unwrap_generic(expr.obj.smartcasts.last())
|
||||||
cast_sym := g.table.sym(exp_typ)
|
cast_sym := g.table.sym(exp_typ)
|
||||||
if cast_sym.info is ast.Aggregate {
|
if cast_sym.info is ast.Aggregate {
|
||||||
exp_typ = cast_sym.info.types[g.aggregate_type_idx]
|
exp_typ = cast_sym.info.types[g.aggregate_type_idx]
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
interface Any {}
|
||||||
|
|
||||||
|
struct ConcreteA {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConcreteB {
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Container {
|
||||||
|
concrete_a Any
|
||||||
|
concrete_b Any
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cast_struct<T>(any_struct Any) &T {
|
||||||
|
if any_struct is T {
|
||||||
|
return any_struct
|
||||||
|
}
|
||||||
|
panic('cannot cast')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_empty_interface_to_multi_struct() {
|
||||||
|
concrete_a := cast_struct<ConcreteA>(ConcreteA{12345})
|
||||||
|
concrete_b := cast_struct<ConcreteB>(ConcreteB{54321})
|
||||||
|
println(concrete_a.a)
|
||||||
|
println(concrete_b.b)
|
||||||
|
assert concrete_a.a == 12345
|
||||||
|
assert concrete_b.b == 54321
|
||||||
|
}
|
Loading…
Reference in New Issue