diff options
| author | gingerBill <bill@gingerbill.org> | 2023-06-06 22:42:04 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2023-06-06 22:42:04 +0100 |
| commit | 4a75a1e839252e7719e4126e0e98dd647850f91d (patch) | |
| tree | c842ea0f1924563be025ef49726d98d9f2763e94 /src/check_builtin.cpp | |
| parent | 60ec3594ab05faaa46c7cac50e87571ab3f5eaa6 (diff) | |
| parent | 6a2ff3a3711e3da6bc9f2be9d9a67361b3ff9bd5 (diff) | |
Merge branch 'master' into separate-int-word-sizes
Diffstat (limited to 'src/check_builtin.cpp')
| -rw-r--r-- | src/check_builtin.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5f9715959..46ee6b7f9 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4843,6 +4843,89 @@ 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 = array_make<Type *>(permanent_allocator(), 0, ux->Union.variants.count+uy->Union.variants.count); + for (Type *t : ux->Union.variants) { + array_add(&variants, t); + } + for (Type *t : uy->Union.variants) { + bool ok = true; + for (Type *other_t : ux->Union.variants) { + if (are_types_identical(other_t, t)) { + ok = false; + break; + } + } + if (ok) { + array_add(&variants, t); + } + + } + merged_union->Union.variants = slice_from_array(variants); + + operand->mode = Addressing_Type; + operand->type = merged_union; + } + break; + case BuiltinProc_type_is_boolean: case BuiltinProc_type_is_integer: |