checker, cgen: fix aggregate var handling on match branch (fix #23768) (#23787)

This commit is contained in:
Felipe Pena 2025-02-23 07:15:10 -03:00 committed by GitHub
parent 5376a55cef
commit 89d1aac5bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 44 additions and 10 deletions

View file

@ -884,6 +884,7 @@ pub enum ComptimeVarKind {
generic_param // generic fn parameter
generic_var // generic var
smartcast // smart cast when used in `is v` (when `v` is from $for .variants)
aggregate // aggregate var
}
@[minify]

View file

@ -4331,6 +4331,8 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
is_inherited = expr.obj.is_inherited
ct_type_var = if is_comptime {
.smartcast
} else if c.table.type_kind(to_type_) == .aggregate {
.aggregate
} else {
.no_comptime
}

View file

@ -32,7 +32,7 @@ fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) u8 {
return `s`
}
if ftyp in [ast.string_type, ast.bool_type]
|| sym.kind in [.enum, .array, .array_fixed, .struct, .map, .multi_return, .sum_type, .interface, .none]
|| sym.kind in [.enum, .array, .array_fixed, .struct, .map, .multi_return, .sum_type, .interface, .aggregate, .none]
|| ftyp.has_option_or_result() || sym.has_method('str') {
return `s`
} else {

View file

@ -5022,7 +5022,7 @@ fn (mut g Gen) ident(node ast.Ident) {
if node.info is ast.IdentVar {
if node.obj is ast.Var {
if !g.is_assign_lhs
&& node.obj.ct_type_var !in [.smartcast, .generic_param, .no_comptime] {
&& node.obj.ct_type_var !in [.smartcast, .generic_param, .no_comptime, .aggregate] {
comptime_type := g.type_resolver.get_type(node)
if comptime_type.has_flag(.option) {
if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent {

View file

@ -836,11 +836,7 @@ fn (mut g Gen) infix_expr_in_optimization(left ast.Expr, left_type ast.Type, rig
fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) {
mut left_sym := g.table.sym(g.unwrap_generic(g.type_resolver.get_type_or_default(node.left,
node.left_type)))
is_aggregate := left_sym.kind == .aggregate
if is_aggregate {
parent_left_type := (left_sym.info as ast.Aggregate).sum_type
left_sym = g.table.sym(parent_left_type)
}
is_aggregate := node.left is ast.Ident && g.comptime.get_ct_type_var(node.left) == .aggregate
right_sym := g.table.sym(node.right_type)
if left_sym.kind == .interface && right_sym.kind == .interface {
g.gen_interface_is_op(node)
@ -880,7 +876,7 @@ fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) {
sub_sym := g.table.sym(sub_type)
g.write('_${left_sym.cname}_${sub_sym.cname}_index')
return
} else if left_sym.kind == .sum_type {
} else if left_sym.kind == .sum_type || is_aggregate {
g.write('_typ ${cmp_op} ')
}
if node.right is ast.None {

View file

@ -218,6 +218,9 @@ fn (mut g Gen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var str
}
cur_expr := unsafe { &branch.exprs[sumtype_index] }
if cond_sym.kind == .sum_type {
if cur_expr is ast.TypeNode {
g.type_resolver.update_ct_type(cond_var, cur_expr.typ)
}
g.write('${dot_or_ptr}_typ == ')
if cur_expr is ast.None {
g.write('${ast.none_type.idx()} /* none */')

View file

@ -0,0 +1,25 @@
module main
type Value = int | i64 | u64 | string | []u8
fn d(val Value) string {
match val {
int, i64, u64, []u8 {
s := sizeof(val)
x := val
return 'Value is number or byte array, size=${s} ${x}'
}
string {
x := val
return 'Value is string: ${x}'
}
}
}
fn test_main() {
assert d(Value(0)) == 'Value is number or byte array, size=4 0'
assert d(Value(i64(1))) == 'Value is number or byte array, size=8 1'
assert d(Value(u64(2))) == 'Value is number or byte array, size=8 2'
assert d(Value([u8(1), 2])) == 'Value is number or byte array, size=32 [1, 2]'
assert d(Value('')) == 'Value is string: '
}

View file

@ -41,6 +41,6 @@ fn test_typeof_aggregate() {
assert rets.len == 3
assert rets[0] == 'The type of `a` is `Foo`'
assert rets[1] == 'The type of `a` is `(Bar | Baz | Bazaar)` and its text says bar'
assert rets[2] == 'The type of `a` is `(Bar | Baz | Bazaar)` and its text says baz'
assert rets[1] == 'The type of `a` is `Bar` and its text says bar'
assert rets[2] == 'The type of `a` is `Baz` and its text says baz'
}

View file

@ -190,6 +190,13 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type {
ctyp
}
}
.aggregate {
t.get_ct_type_or_default(node.name, if node.obj.smartcasts.len > 0 {
node.obj.smartcasts.last()
} else {
node.obj.typ
})
}
.key_var, .value_var {
// key and value variables from normal for stmt
t.get_ct_type_or_default(node.name, ast.void_type)