From feb008ab6e5fe15e84735979560ab9f2cd651400 Mon Sep 17 00:00:00 2001 From: korvahkh <92224397+korvahkh@users.noreply.github.com> Date: Sat, 8 Aug 2026 20:19:18 -0500 Subject: [PATCH] Add tests for constant unions --- tests/internal/test_union_const.odin | 192 +++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/tests/internal/test_union_const.odin b/tests/internal/test_union_const.odin index 3f3260993..7180a0ce3 100644 --- a/tests/internal/test_union_const.odin +++ b/tests/internal/test_union_const.odin @@ -52,3 +52,195 @@ union_constant_as_a_global_initializer :: proc(t: ^testing.T) { if v, ok := G.(int); testing.expect(t, ok, "global lost its variant") { testing.expect_value(t, v, 3) } if v, ok := GS.(string); testing.expect(t, ok, "string global lost its variant") { testing.expect_value(t, v, "hello") } } + +A :: union {B, bool} +B :: union {C, int } +C :: struct{} + +@(test) +union_const_access :: proc(t: ^testing.T) { + X :: struct{x: A}{B(C{})} + testing.expect_value(t, X.x, A(B(C{}))) + + E :: enum {y} + Y : [E]A : {.y = true} + testing.expect_value(t, Y[.y], A(true)) +} + +@(test) +nested_union_implicit_cast :: proc(t: ^testing.T) { + Av: A: Bv + Bv: B: Cv + Cv: C: {} + testing.expect_value(t, Av, A(B(C{}))) +} + +@(test) +union_ternary :: proc(t: ^testing.T) { + E0 : A = B(C{}) if true else B(C{}) + E1 : A = true if true else true + E2 := A(B(C{}) if true else B(C{})) + E3 := A(true if true else true) + + testing.expect_value(t, E0, A(B(C{}))) + testing.expect_value(t, E1, A(true)) + testing.expect_value(t, E2, A(B(C{}))) + testing.expect_value(t, E3, A(true)) +} + +@(test) +union_array :: proc(t: ^testing.T) { + C0: [2][2]A: B(C{}) + C1: struct {x: [2][2]A} : {B(C{})} + testing.expect_value(t, C0, [2][2]A{0..<2 = B(C{})}) +} + +@(test) +union_multi_level_cast :: proc(t: ^testing.T) { + UI :: union {int, bool} + foo: Maybe(UI): 1 + bar: union{UI}: 2 + baz: UI: 3 + qux: struct{ui: UI}: {4} + testing.expect_value(t, foo, 1) + testing.expect_value(t, bar, 2) + testing.expect_value(t, baz, 3) + testing.expect_value(t, qux.ui, 4) +} + +@(test) +union_args :: proc(t: ^testing.T) { + implicit_bool :: proc(a: A = true ) -> A { return a.(bool) } + explicit_bool :: proc(a: A = A(true)) -> A { return a.(bool) } + nil_union :: proc(a: A = B{} ) -> A { return a.(B ) } + struct_union :: proc(a: A = B(C{}) ) -> A { return a.(B ) } + + testing.expect_value(t, implicit_bool(), true) + testing.expect_value(t, explicit_bool(), true) + testing.expect_value(t, nil_union (), B{}) + testing.expect_value(t, struct_union (), B(C{})) + + testing.expect_value(t, implicit_bool(true ), true) + testing.expect_value(t, explicit_bool(A(true)), true) + testing.expect_value(t, nil_union (B{} ), B{}) + testing.expect_value(t, struct_union (B(C{}) ), B(C{})) + + testing.expect_value(t, implicit_bool(a=true ), true) + testing.expect_value(t, explicit_bool(a=A(true)), true) + testing.expect_value(t, nil_union (a=B{} ), B{}) + testing.expect_value(t, struct_union (a=B(C{}) ), B(C{})) +} + +@(test) +union_in_aggregates :: proc(t: ^testing.T) { + S :: struct { + x : union { int, string }, + y : u128, + } + U :: struct #packed {v: [2]S, n: i64} + V :: struct {x: [dynamic; 2]S} + + s := [dynamic; 2]S { {x=1} } + u := U { {{x=1}, {x=2}}, 2 } + v := V{x = { {x=1} }} + + testing.expect_value(t, s [0], S{x=1}) + testing.expect_value(t, u.v[1], S{x=2}) + testing.expect_value(t, v.x[0], S{x=1}) +} + +@(test) +union_named_constants :: proc(t: ^testing.T) { + Inner_Left :: enum { + a, + b, + } + + Inner_Right :: enum { + c, + d, + } + + Inner :: union { + Inner_Left, + Inner_Right, + } + + Outer :: union { + Inner, + int, + } + + Atom :: struct { + token: Outer, + } + + Promoted_Value :: union { + int, + f32, + string, + } + + Promoted_Inner :: struct { + value: Promoted_Value, + padding0: int, + padding1: int, + } + + Promoted_Outer :: struct { + using inner: Promoted_Inner, + } + + NAMED_INNER :: Inner(Inner_Left.a) + + DIRECT_ATOMS :: [?]Atom{{token = Inner(Inner_Left.a)}} + + NAMED_ATOMS :: [?]Atom{{token = NAMED_INNER}} + + INDEXED_OUTERS :: [1]Outer { + 0 = Inner(Inner_Left.a), + } + + RANGED_OUTERS :: [1]Outer { + 0..=0 = Inner(Inner_Left.a), + } + + Outer_Index :: enum {first} + + ENUMERATED_OUTERS :: [Outer_Index]Outer { + .first = Inner(Inner_Left.a), + } + + RANGED_ENUMERATED_OUTERS :: [Outer_Index]Outer { + .first..=.first = Inner(Inner_Left.a), + } + + FIXED_CAPACITY_OUTERS :: [dynamic; 1]Outer{ + 0 = Inner(Inner_Left.a), + } + + RANGED_FIXED_CAPACITY_OUTERS :: [dynamic; 1]Outer{ + 0..=0 = Inner(Inner_Left.a), + } + + POSITIONAL_FIXED_CAPACITY_OUTERS :: [dynamic; 1]Outer{ + Inner(Inner_Left.a), + } + + testing.expect_value(t, DIRECT_ATOMS[0], Atom{token = Inner(.a)}) + testing.expect_value(t, NAMED_ATOMS[0], Atom{token = NAMED_INNER}) + testing.expect_value(t, INDEXED_OUTERS[0], Inner(.a)) + testing.expect_value(t, RANGED_OUTERS[0], Inner(.a)) + testing.expect_value(t, ENUMERATED_OUTERS[.first], Inner(.a)) + testing.expect_value(t, RANGED_ENUMERATED_OUTERS[.first], Inner(.a)) + fco := FIXED_CAPACITY_OUTERS + rfco := RANGED_FIXED_CAPACITY_OUTERS + testing.expect_value(t, fco[0], Inner(.a)) + testing.expect_value(t, rfco[0], Inner(.a)) + testing.expect_value(t, POSITIONAL_FIXED_CAPACITY_OUTERS[0], Inner(.a)) + testing.expect_value(t, Promoted_Outer { + value = Promoted_Value(int(1)), + }, Promoted_Outer { + inner = {Promoted_Value(int(1)), 0, 0}, + }) +}