checker, cgen: fix generic empty interface to multi struct (#14132)
							parent
							
								
									2c59d47fc1
								
							
						
					
					
						commit
						e0963381ec
					
				| 
						 | 
				
			
			@ -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