diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index de368f2342..218076af0a 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 26c656d6ec..2b715e9af2 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 } diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index 9209ac7d2c..cf12236d85 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -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 { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index ab8428d01f..db208129da 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -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 { diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index f3a2227f89..c1fa6a72a7 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -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 { diff --git a/vlib/v/gen/c/match.v b/vlib/v/gen/c/match.v index 5795489ba4..772e6271f6 100644 --- a/vlib/v/gen/c/match.v +++ b/vlib/v/gen/c/match.v @@ -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 */') diff --git a/vlib/v/tests/comptime/comptime_aggregate_var_test.v b/vlib/v/tests/comptime/comptime_aggregate_var_test.v new file mode 100644 index 0000000000..6ba35886cb --- /dev/null +++ b/vlib/v/tests/comptime/comptime_aggregate_var_test.v @@ -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: ' +} diff --git a/vlib/v/tests/typeof_aggregate_test.v b/vlib/v/tests/typeof_aggregate_test.v index 839d874288..8a21f0f645 100644 --- a/vlib/v/tests/typeof_aggregate_test.v +++ b/vlib/v/tests/typeof_aggregate_test.v @@ -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' } diff --git a/vlib/v/type_resolver/type_resolver.v b/vlib/v/type_resolver/type_resolver.v index 4d9cb7df31..01530ee95f 100644 --- a/vlib/v/type_resolver/type_resolver.v +++ b/vlib/v/type_resolver/type_resolver.v @@ -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)