diff options
Diffstat (limited to 'src/check_builtin.cpp')
| -rw-r--r-- | src/check_builtin.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index dd9896927..f01b61128 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3243,6 +3243,186 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_compress_values: { + Operand *ops = gb_alloc_array(temporary_allocator(), Operand, ce->args.count); + + isize value_count = 0; + + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + Operand *op = &ops[i]; + check_multi_expr(c, op, arg); + if (op->mode == Addressing_Invalid) { + return false; + } + + if (op->type == nullptr || op->type == t_invalid) { + gbString s = expr_to_string(op->expr); + error(op->expr, "Invalid expression to '%.*s', got %s", LIT(builtin_name), s); + gb_string_free(s); + } + if (is_type_tuple(op->type)) { + value_count += op->type->Tuple.variables.count; + } else { + value_count += 1; + } + } + + GB_ASSERT(value_count >= 1); + + if (value_count == 1) { + *operand = ops[0]; + break; + } + + if (type_hint != nullptr) { + Type *th = base_type(type_hint); + if (th->kind == Type_Struct) { + if (value_count == th->Struct.fields.count) { + isize index = 0; + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + for (Entity *v : op->type->Tuple.variables) { + Operand x = {}; + x.mode = Addressing_Value; + x.type = v->type; + check_assignment(c, &x, th->Struct.fields[index++]->type, builtin_name); + if (x.mode == Addressing_Invalid) { + return false; + } + } + } else { + check_assignment(c, op, th->Struct.fields[index++]->type, builtin_name); + if (op->mode == Addressing_Invalid) { + return false; + } + } + } + + operand->type = type_hint; + operand->mode = Addressing_Value; + break; + } + } else if (is_type_array_like(th)) { + if (cast(i64)value_count == get_array_type_count(th)) { + Type *elem = base_array_type(th); + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + for (Entity *v : op->type->Tuple.variables) { + Operand x = {}; + x.mode = Addressing_Value; + x.type = v->type; + check_assignment(c, &x, elem, builtin_name); + if (x.mode == Addressing_Invalid) { + return false; + } + } + } else { + check_assignment(c, op, elem, builtin_name); + if (op->mode == Addressing_Invalid) { + return false; + } + } + } + + operand->type = type_hint; + operand->mode = Addressing_Value; + break; + } + } + } + + bool all_types_the_same = true; + Type *last_type = nullptr; + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + if (last_type == nullptr) { + op->type->Tuple.variables[0]->type; + } + for (Entity *v : op->type->Tuple.variables) { + if (!are_types_identical(last_type, v->type)) { + all_types_the_same = false; + break; + } + last_type = v->type; + } + } else { + if (last_type == nullptr) { + last_type = op->type; + } else { + if (!are_types_identical(last_type, op->type)) { + all_types_the_same = false; + break; + } + last_type = op->type; + } + } + } + + if (all_types_the_same) { + operand->type = alloc_type_array(last_type, value_count); + operand->mode = Addressing_Value; + } else { + Type *st = alloc_type_struct_complete(); + st->Struct.fields = slice_make<Entity *>(permanent_allocator(), value_count); + st->Struct.tags = gb_alloc_array(permanent_allocator(), String, value_count); + st->Struct.offsets = gb_alloc_array(permanent_allocator(), i64, value_count); + + Scope *scope = create_scope(c->info, nullptr); + + Token token = {}; + token.kind = Token_Ident; + token.pos = ast_token(call).pos; + + isize index = 0; + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + for (Entity *v : op->type->Tuple.variables) { + Type *t = default_type(v->type); + if (is_type_untyped(t)) { + gbString s = expr_to_string(op->expr); + error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name)); + gb_string_free(s); + return false; + } + + gbString s = gb_string_make_reserve(permanent_allocator(), 32); + s = gb_string_append_fmt(s, "v%lld", cast(long long)index); + token.string = make_string_c(s); + Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved); + st->Struct.fields[index++] = e; + } + } else { + Type *t = default_type(op->type); + if (is_type_untyped(t)) { + gbString s = expr_to_string(op->expr); + error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name)); + gb_string_free(s); + return false; + } + + gbString s = gb_string_make_reserve(permanent_allocator(), 32); + s = gb_string_append_fmt(s, "v%lld", cast(long long)index); + token.string = make_string_c(s); + Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved); + st->Struct.fields[index++] = e; + } + } + + + gb_unused(type_size_of(st)); + + operand->type = st; + operand->mode = Addressing_Value; + } + break; + } + + case BuiltinProc_min: { // min :: proc($T: typeid) -> ordered // min :: proc(a: ..ordered) -> ordered |