checker/gen: fix smartcast pointer sumtype (#8260)

pull/8244/head^2
Daniel Däschle 2021-01-21 21:31:25 +01:00 committed by GitHub
parent 6b1956fb60
commit 3ee7bc960f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 11 deletions

View File

@ -423,7 +423,12 @@ pub:
is_arg bool // fn args should not be autofreed
pub mut:
typ table.Type
orig_type table.Type // original sumtype type; 0 if it's not a sumtype
sum_type_casts []table.Type // nested sum types require nested smart casting, for that a list of types is needed
// TODO: move this to a real docs site later
// 10 <- original type (orig_type)
// [11, 12, 13] <- cast order (sum_type_casts)
// 12 <- the current casted type (typ)
pos token.Position
is_used bool
is_changed bool // to detect mutable vars that are never changed
@ -442,6 +447,11 @@ pub:
pos token.Position
typ table.Type
sum_type_casts []table.Type // nested sum types require nested smart casting, for that a list of types is needed
orig_type table.Type // original sumtype type; 0 if it's not a sumtype
// TODO: move this to a real docs site later
// 10 <- original type (orig_type)
// [11, 12, 13] <- cast order (sum_type_casts)
// 12 <- the current casted type (typ)
}
pub struct GlobalField {

View File

@ -4150,6 +4150,7 @@ fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type tab
mut is_mut := false
mut sum_type_casts := []table.Type{}
expr_sym := c.table.get_type_symbol(expr.expr_type)
mut orig_type := 0
if field := c.table.struct_find_field(expr_sym, expr.field_name) {
if field.is_mut {
root_ident := expr.root_ident()
@ -4157,6 +4158,9 @@ fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type tab
is_mut = v.is_mut
}
}
if orig_type == 0 {
orig_type = field.typ
}
}
if field := scope.find_struct_field(expr.expr_type, expr.field_name) {
sum_type_casts << field.sum_type_casts
@ -4170,6 +4174,7 @@ fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type tab
typ: cur_type
sum_type_casts: sum_type_casts
pos: expr.pos
orig_type: orig_type
})
}
}
@ -4177,11 +4182,14 @@ fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type tab
mut is_mut := false
mut sum_type_casts := []table.Type{}
mut is_already_casted := false
if expr.obj is ast.Var {
v := expr.obj as ast.Var
is_mut = v.is_mut
sum_type_casts << v.sum_type_casts
is_already_casted = v.pos.pos == expr.pos.pos
mut orig_type := 0
if mut expr.obj is ast.Var {
is_mut = expr.obj.is_mut
sum_type_casts << expr.obj.sum_type_casts
is_already_casted = expr.obj.pos.pos == expr.pos.pos
if orig_type == 0 {
orig_type = expr.obj.typ
}
}
// smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || expr.is_mut) && !is_already_casted {
@ -4193,6 +4201,7 @@ fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type tab
is_used: true
is_mut: expr.is_mut
sum_type_casts: sum_type_casts
orig_type: orig_type
})
}
}

View File

@ -2939,6 +2939,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
return
}
mut sum_type_deref_field := ''
mut sum_type_dot := '.'
if f := g.table.struct_find_field(sym, node.field_name) {
field_sym := g.table.get_type_symbol(f.typ)
if field_sym.kind == .sum_type {
@ -2946,6 +2947,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
// check first if field is sum type because scope searching is expensive
scope := g.file.scope.innermost(node.pos.pos)
if field := scope.find_struct_field(node.expr_type, node.field_name) {
if field.orig_type.is_ptr() {
sum_type_dot = '->'
}
// union sum type deref
for i, typ in field.sum_type_casts {
g.write('(*')
@ -2957,7 +2961,6 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
if mut cast_sym.info is table.Aggregate {
agg_sym := g.table.get_type_symbol(cast_sym.info.types[g.aggregate_type_idx])
sum_type_deref_field += '_$agg_sym.cname'
// sum_type_deref_field += '_${cast_sym.info.types[g.aggregate_type_idx]}'
} else {
sum_type_deref_field += '_$cast_sym.cname'
}
@ -2997,7 +3000,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
}
g.write(c_name(node.field_name))
if sum_type_deref_field != '' {
g.write('.$sum_type_deref_field)')
g.write('$sum_type_dot$sum_type_deref_field)')
}
}
@ -3782,10 +3785,14 @@ fn (mut g Gen) ident(node ast.Ident) {
}
for i, typ in v.sum_type_casts {
cast_sym := g.table.get_type_symbol(typ)
mut is_ptr := false
if i == 0 {
g.write(name)
if v.orig_type.is_ptr() {
is_ptr = true
}
dot := if v.typ.is_ptr() { '->' } else { '.' }
}
dot := if is_ptr { '->' } else { '.' }
if mut cast_sym.info is table.Aggregate {
sym := g.table.get_type_symbol(cast_sym.info.types[g.aggregate_type_idx])
g.write('${dot}_$sym.cname')

View File

@ -253,3 +253,51 @@ fn test_nested_sumtype_selector() {
assert false
}
}
struct Foo1 {
a int
}
struct Foo2 {
a int
}
struct Bar1 {
a int
}
struct Bar2 {
a int
}
type Sum1 = Foo1 | Foo2
type Sum2 = Bar1 | Bar2
type SumAll = Sum1 | Sum2
struct All_in_one {
pub mut:
ptrs []&SumAll
ptr &SumAll
}
fn test_nested_pointer_smartcast() {
mut s := All_in_one{
ptr: &Sum1(Foo1{a: 1})
ptrs: [&SumAll(Sum2(Bar1{a: 3}))]
}
if mut s.ptr is Sum1 {
if mut s.ptr is Foo1 {
assert s.ptr.a == 1
}
}
a := s.ptrs[0]
if a is Sum1 {
if a is Foo1{
assert a.a == 3
}
}
}