checker, cgen: fix generic empty interface to multi struct (#14132)

master
yuyi 2022-04-22 16:02:51 +08:00 committed by GitHub
parent 9b565bf765
commit 5dce091379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 9 deletions

View File

@ -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)

View File

@ -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
} }

View File

@ -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'

View File

@ -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]

View File

@ -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]

View File

@ -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
}