diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 890a6881d..93cd0e505 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -192,6 +192,7 @@ type_map_info :: proc($T: typeid/map[$K]$V) -> ^runtime.Map_Info --- type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- +type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5f9715959..0f8cdfd69 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4843,6 +4843,75 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } operand->mode = Addressing_Type; break; + case BuiltinProc_type_merge: + { + operand->mode = Addressing_Type; + operand->type = t_invalid; + + Operand x = {}; + Operand y = {}; + check_expr_or_type(c, &x, ce->args[0]); + check_expr_or_type(c, &y, ce->args[1]); + if (x.mode != Addressing_Type) { + error(x.expr, "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (y.mode != Addressing_Type) { + error(y.expr, "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + + if (is_type_polymorphic(x.type)) { + gbString t = type_to_string(x.type); + error(x.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (is_type_polymorphic(y.type)) { + gbString t = type_to_string(y.type); + error(y.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (!is_type_union(x.type)) { + gbString t = type_to_string(x.type); + error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (!is_type_union(y.type)) { + gbString t = type_to_string(y.type); + error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + Type *ux = base_type(x.type); + Type *uy = base_type(y.type); + GB_ASSERT(ux->kind == Type_Union); + GB_ASSERT(uy->kind == Type_Union); + + i64 custom_align = gb_max(ux->Union.custom_align, uy->Union.custom_align); + if (ux->Union.kind != uy->Union.kind) { + error(x.expr, "Union kinds must match, got %s vs %s", union_type_kind_strings[ux->Union.kind], union_type_kind_strings[uy->Union.kind]); + } + + Type *merged_union = alloc_type_union(); + + merged_union->Union.node = call; + merged_union->Union.scope = create_scope(c->info, c->scope); + merged_union->Union.kind = ux->Union.kind; + merged_union->Union.custom_align = custom_align; + + auto variants = slice_make(permanent_allocator(), ux->Union.variants.count+uy->Union.variants.count); + slice_copy(&variants, ux->Union.variants, 0); + slice_copy(&variants, uy->Union.variants, ux->Union.variants.count); + merged_union->Union.variants = variants; + + operand->mode = Addressing_Type; + operand->type = merged_union; + } + break; + case BuiltinProc_type_is_boolean: case BuiltinProc_type_is_integer: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0db12aba0..1552b1ef5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1067,7 +1067,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ if (check_is_assignable_to(c, operand, type)) { if (operand->mode == Addressing_Type && is_type_typeid(type)) { - add_type_info_type(c, operand->type); + add_type_info_type(c, operand->type); add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); } } else { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 72f001c70..edd046087 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -203,6 +203,7 @@ BuiltinProc__type_begin, BuiltinProc_type_elem_type, BuiltinProc_type_convert_variants_to_pointers, + BuiltinProc_type_merge, BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_boolean, @@ -501,6 +502,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_merge"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/parser.hpp b/src/parser.hpp index 5302fd274..aea3bbf21 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -356,6 +356,15 @@ enum UnionTypeKind : u8 { UnionType_Normal = 0, UnionType_no_nil = 2, UnionType_shared_nil = 3, + + UnionType_COUNT +}; + +gb_global char const *union_type_kind_strings[UnionType_COUNT] = { + "(normal)", + "#maybe", + "#no_nil", + "#shared_nil", }; #define AST_KINDS \