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)
|
||||
} else if node.op == .key_is {
|
||||
right_expr := node.right
|
||||
mut right_type := match right_expr {
|
||||
right_type := match right_expr {
|
||||
ast.TypeNode {
|
||||
right_expr.typ
|
||||
}
|
||||
|
@ -308,11 +308,10 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
|||
ast.Type(0)
|
||||
}
|
||||
}
|
||||
right_type = c.unwrap_generic(right_type)
|
||||
if right_type != ast.Type(0) {
|
||||
left_sym := c.table.sym(node.left_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 {
|
||||
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 {
|
||||
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)
|
||||
expr_str := c.table.type_to_str(expr_type)
|
||||
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 expr_idxs := []int{}
|
||||
for i, expr in node.exprs {
|
||||
typ := c.expr(expr)
|
||||
mut typ := c.expr(expr)
|
||||
if typ == ast.void_type {
|
||||
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
|
||||
}
|
||||
} 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
|
||||
expr_idxs << i
|
||||
}
|
||||
|
|
|
@ -3286,7 +3286,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
|||
if field_sym.kind == .sum_type {
|
||||
g.write('*')
|
||||
}
|
||||
cast_sym := g.table.sym(typ)
|
||||
cast_sym := g.table.sym(g.unwrap_generic(typ))
|
||||
if i != 0 {
|
||||
dot := if field.typ.is_ptr() { '->' } else { '.' }
|
||||
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)
|
||||
return
|
||||
} 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)
|
||||
if cast_sym.info is ast.Aggregate {
|
||||
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 {
|
||||
typ = expr.obj.typ
|
||||
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)
|
||||
if cast_sym.info is ast.Aggregate {
|
||||
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 {
|
||||
exp_typ = expr.obj.typ
|
||||
} 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)
|
||||
if cast_sym.info is ast.Aggregate {
|
||||
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