diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-10-08 12:27:03 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-10-08 12:27:03 +0100 |
| commit | 4e42d7df4303470dec5b3c354a9469699f6abf8d (patch) | |
| tree | de88a4b917a9f7d29b34e2db03a50d05f299b666 /src/check_expr.cpp | |
| parent | 580ee5cc4afb6ee15785e57747559d885af16d55 (diff) | |
Minor code reorganization
Diffstat (limited to 'src/check_expr.cpp')
| -rw-r--r-- | src/check_expr.cpp | 2415 |
1 files changed, 6 insertions, 2409 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp index eb1a5dcdc..7b1b3f271 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -56,9 +56,11 @@ void check_expr_or_type (Checker *c, Operand *operand, AstNode * ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); void check_expr_with_type_hint (Checker *c, Operand *o, AstNode *e, Type *t); Type * check_type (Checker *c, AstNode *expression, Type *named_type = nullptr); +Type * make_optional_ok_type(gbAllocator a, Type *value); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint); Entity * check_ident (Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name); +Entity * find_polymorphic_struct_entity(Checker *c, Type *original_type, isize param_count, Array<Operand> ordered_operands); void check_not_tuple (Checker *c, Operand *operand); void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level); gbString expr_to_string (AstNode *expression); @@ -73,9 +75,13 @@ void check_stmt_list (Checker *c, Array<AstNode *> stmts, u32 void check_init_constant (Checker *c, Entity *e, Operand *operand); bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); bool check_procedure_type (Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands = nullptr); +void check_struct_type (Checker *c, Type *struct_type, AstNode *node, Array<Operand> *poly_operands, + Type *named_type = nullptr, Type *original_type_for_poly = nullptr); CallArgumentData check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call); Type * check_init_variable (Checker *c, Entity *e, Operand *operand, String context_name); + + void error_operand_not_expression(Operand *o) { if (o->mode == Addressing_Type) { gbString err = expr_to_string(o->expr); @@ -741,1193 +747,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } -void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *> *entity_map) { - t = base_type(type_deref(t)); - gbString str = nullptr; - defer (gb_string_free(str)); - if (node != nullptr) { - str = expr_to_string(node); - } - - if (t->kind == Type_Struct) { - for_array(i, t->Struct.fields) { - Entity *f = t->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - String name = f->token.string; - HashKey key = hash_string(name); - Entity **found = map_get(entity_map, key); - if (found != nullptr && name != "_") { - Entity *e = *found; - // TODO(bill): Better type error - if (str != nullptr) { - error(e->token, "`%.*s` is already declared in `%s`", LIT(name), str); - } else { - error(e->token, "`%.*s` is already declared`", LIT(name)); - } - } else { - map_set(entity_map, key, f); - add_entity(c, c->context.scope, nullptr, f); - if (f->flags & EntityFlag_Using) { - populate_using_entity_map(c, node, f->type, entity_map); - } - } - } - } - -} - - -void check_struct_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields, Map<Entity *> *entity_map, AstNode *struct_node, String context, bool allow_default_values) { - GB_ASSERT(fields != nullptr); - if (decl->kind == AstNode_WhenStmt) { - ast_node(ws, WhenStmt, decl); - Operand operand = {Addressing_Invalid}; - check_expr(c, &operand, ws->cond); - if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) { - error(ws->cond, "Non-constant boolean `when` condition"); - return; - } - if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) { - error(ws->cond, "Invalid body for `when` statement"); - return; - } - if (operand.value.kind == ExactValue_Bool && - operand.value.value_bool) { - for_array(i, ws->body->BlockStmt.stmts) { - AstNode *stmt = ws->body->BlockStmt.stmts[i]; - check_struct_field_decl(c, stmt, fields, entity_map, struct_node, context, allow_default_values); - } - } else if (ws->else_stmt) { - switch (ws->else_stmt->kind) { - case AstNode_BlockStmt: - for_array(i, ws->else_stmt->BlockStmt.stmts) { - AstNode *stmt = ws->else_stmt->BlockStmt.stmts[i]; - check_struct_field_decl(c, stmt, fields, entity_map, struct_node, context, allow_default_values); - } - break; - case AstNode_WhenStmt: - check_struct_field_decl(c, ws->else_stmt, fields, entity_map, struct_node, context, allow_default_values); - break; - default: - error(ws->else_stmt, "Invalid `else` statement in `when` statement"); - break; - } - } - } - - if (decl->kind != AstNode_ValueDecl) { - return; - } - - - ast_node(vd, ValueDecl, decl); - - if (!vd->is_mutable) return; - - bool is_using = (vd->flags&VarDeclFlag_using) != 0; - - if (is_using && vd->names.count > 1) { - error(vd->names[0], "Cannot apply `using` to more than one of the same type"); - is_using = false; - } - - bool arity_ok = check_arity_match(c, vd); - - if (vd->values.count > 0 && !allow_default_values) { - error(vd->values[0], "Default values are not allowed within a %.*s", LIT(context)); - } - - - Type *type = nullptr; - if (vd->type != nullptr) { - type = check_type(c, vd->type); - } else if (!allow_default_values) { - error(vd->names[0], "Expected a type for this field"); - type = t_invalid; - } - - if (type != nullptr) { - if (is_type_empty_union(type)) { - error(vd->names[0], "An empty union cannot be used as a field type in %.*s", LIT(context)); - type = t_invalid; - } - if (!c->context.allow_polymorphic_types && is_type_polymorphic(base_type(type))) { - error(vd->names[0], "Invalid use of a polymorphic type in %.*s", LIT(context)); - type = t_invalid; - } - } - - Array<Operand> default_values = {}; - defer (array_free(&default_values)); - if (vd->values.count > 0 && allow_default_values) { - array_init(&default_values, heap_allocator(), 2*vd->values.count); - - Type *type_hint = nullptr; - if (type != t_invalid && type != nullptr) { - type_hint = type; - } - - for_array(i, vd->values) { - AstNode *v = vd->values[i]; - Operand o = {}; - - check_expr_base(c, &o, v, type_hint); - check_not_tuple(c, &o); - - if (o.mode == Addressing_NoValue) { - error_operand_no_value(&o); - } else { - if (o.mode == Addressing_Value && o.type->kind == Type_Tuple) { - // NOTE(bill): Tuples are not first class thus never named - for_array(index, o.type->Tuple.variables) { - Operand single = {Addressing_Value}; - single.type = o.type->Tuple.variables[index]->type; - single.expr = v; - array_add(&default_values, single); - } - } else { - array_add(&default_values, o); - } - } - } - } - - - isize name_field_index = 0; - for_array(name_index, vd->names) { - AstNode *name = vd->names[name_index]; - if (!ast_node_expect(name, AstNode_Ident)) { - return; - } - - Token name_token = name->Ident.token; - - Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)fields->count); - e->identifier = name; - - if (name_field_index < default_values.count) { - Operand a = default_values[name_field_index]; - Operand b = default_values[name_field_index]; - check_init_variable(c, e, &b, str_lit("struct field assignment")); - if (is_operand_nil(a)) { - e->Variable.default_is_nil = true; - } else if (is_operand_undef(a)) { - e->Variable.default_is_undef = true; - } else if (b.mode != Addressing_Constant) { - error(b.expr, "Default field value must be a constant"); - } else if (is_type_any(e->type) || is_type_union(e->type)) { - gbString str = type_to_string(e->type); - error(b.expr, "A struct field of type `%s` cannot have a default value", str); - gb_string_free(str); - } else { - e->Variable.default_value = b.value; - } - - name_field_index++; - } - - GB_ASSERT(e->type != nullptr); - GB_ASSERT(is_type_typed(e->type)); - - if (is_blank_ident(name_token)) { - array_add(fields, e); - } else { - HashKey key = hash_string(name_token.string); - Entity **found = map_get(entity_map, key); - if (found != nullptr) { - Entity *e = *found; - // NOTE(bill): Scope checking already checks the declaration but in many cases, this can happen so why not? - // This may be a little janky but it's not really that much of a problem - error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string)); - error(e->token, "\tpreviously declared"); - } else { - map_set(entity_map, key, e); - array_add(fields, e); - add_entity(c, c->context.scope, name, e); - } - add_entity_use(c, name, e); - } - - } - - Entity *using_index_expr = nullptr; - - if (is_using && fields->count > 0) { - Type *first_type = (*fields)[fields->count-1]->type; - Type *t = base_type(type_deref(first_type)); - if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) && - vd->names.count >= 1 && - vd->names[0]->kind == AstNode_Ident) { - Token name_token = vd->names[0]->Ident.token; - if (is_type_indexable(t)) { - bool ok = true; - for_array(emi, entity_map->entries) { - Entity *e = entity_map->entries[emi].value; - if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - if (is_type_indexable(e->type)) { - if (e->identifier != vd->names[0]) { - ok = false; - using_index_expr = e; - break; - } - } - } - } - if (ok) { - using_index_expr = (*fields)[fields->count-1]; - } else { - (*fields)[fields->count-1]->flags &= ~EntityFlag_Using; - error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string)); - } - } else { - gbString type_str = type_to_string(first_type); - error(name_token, "`using` cannot be applied to the field `%.*s` of type `%s`", LIT(name_token.string), type_str); - gb_string_free(type_str); - return; - } - } - - populate_using_entity_map(c, struct_node, type, entity_map); - } -} - -// Returns filled field_count -Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *> params, - isize init_field_capacity, Type *named_type, String context) { - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - Array<Entity *> fields = {}; - array_init(&fields, heap_allocator(), init_field_capacity); - - Map<Entity *> entity_map = {}; - map_init(&entity_map, c->tmp_allocator, 2*init_field_capacity); - - - GB_ASSERT(node->kind == AstNode_StructType); - - isize variable_count = 0; - for_array(i, params) { - AstNode *field = params[i]; - if (ast_node_expect(field, AstNode_Field)) { - ast_node(f, Field, field); - variable_count += gb_max(f->names.count, 1); - } - } - - i32 field_src_index = 0; - for_array(i, params) { - AstNode *param = params[i]; - if (param->kind != AstNode_Field) { - continue; - } - ast_node(p, Field, param); - AstNode *type_expr = p->type; - Type *type = nullptr; - AstNode *default_value = unparen_expr(p->default_value); - ExactValue value = {}; - bool default_is_nil = false; - bool detemine_type_from_operand = false; - - - if (type_expr == nullptr) { - Operand o = {}; - check_expr_or_type(c, &o, default_value); - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - if (default_value->kind == AstNode_ProcLit) { - if (named_type != nullptr) { - value = exact_value_procedure(default_value); - } else { - error(default_value, "A procedure literal cannot be a default value in an anonymous structure"); - } - } else { - Entity *e = nullptr; - if (o.mode == Addressing_Value && is_type_proc(o.type)) { - Operand x = {}; - if (default_value->kind == AstNode_Ident) { - e = check_ident(c, &x, default_value, nullptr, nullptr, false); - } else if (default_value->kind == AstNode_SelectorExpr) { - e = check_selector(c, &x, default_value, nullptr); - } - } - - if (e != nullptr && e->kind == Entity_Procedure) { - value = exact_value_procedure(e->identifier); - add_entity_use(c, e->identifier, e); - } else { - error(default_value, "Default parameter must be a constant"); - } - } - } else { - value = o.value; - } - - type = default_type(o.type); - } else { - type = check_type(c, type_expr); - - if (default_value != nullptr) { - Operand o = {}; - check_expr_with_type_hint(c, &o, default_value, type); - - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - if (default_value->kind == AstNode_ProcLit) { - if (named_type != nullptr) { - value = exact_value_procedure(default_value); - } else { - error(default_value, "A procedure literal cannot be a default value in an anonymous structure"); - } - } else { - Entity *e = nullptr; - if (o.mode == Addressing_Value && is_type_proc(o.type)) { - Operand x = {}; - if (default_value->kind == AstNode_Ident) { - e = check_ident(c, &x, default_value, nullptr, nullptr, false); - } else if (default_value->kind == AstNode_SelectorExpr) { - e = check_selector(c, &x, default_value, nullptr); - } - } - - if (e != nullptr && e->kind == Entity_Procedure) { - value = exact_value_procedure(e->identifier); - add_entity_use(c, e->identifier, e); - } else { - error(default_value, "Default parameter must be a constant"); - } - } - } else { - value = o.value; - } - - check_is_assignable_to(c, &o, type); - } - - if (is_type_polymorphic(type)) { - type = nullptr; - } - } - if (type == nullptr) { - error(params[i], "Invalid parameter type"); - type = t_invalid; - } - if (is_type_untyped(type)) { - if (is_type_untyped_undef(type)) { - error(params[i], "Cannot determine parameter type from ---"); - } else { - error(params[i], "Cannot determine parameter type from a nil"); - } - type = t_invalid; - } - if (is_type_empty_union(type)) { - gbString str = type_to_string(type); - error(params[i], "Invalid use of an empty union `%s`", str); - gb_string_free(str); - type = t_invalid; - } - - bool is_using = (p->flags&FieldFlag_using) != 0; - - for_array(j, p->names) { - AstNode *name = p->names[j]; - if (!ast_node_expect(name, AstNode_Ident)) { - continue; - } - - Token name_token = name->Ident.token; - - Entity *field = nullptr; - field = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, field_src_index); - field->Variable.default_value = value; - field->Variable.default_is_nil = default_is_nil; - - add_entity(c, c->context.scope, name, field); - array_add(&fields, field); - - field_src_index += 1; - } - - Entity *using_index_expr = nullptr; - - if (is_using && p->names.count > 0) { - Type *first_type = fields[fields.count-1]->type; - Type *t = base_type(type_deref(first_type)); - - if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) && - p->names.count >= 1 && - p->names[0]->kind == AstNode_Ident) { - Token name_token = p->names[0]->Ident.token; - if (is_type_indexable(t)) { - bool ok = true; - for_array(emi, entity_map.entries) { - Entity *e = entity_map.entries[emi].value; - if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - if (is_type_indexable(e->type)) { - if (e->identifier != p->names[0]) { - ok = false; - using_index_expr = e; - break; - } - } - } - } - if (ok) { - using_index_expr = fields[fields.count-1]; - } else { - fields[fields.count-1]->flags &= ~EntityFlag_Using; - error(name_token, "Previous `using` for an index expression `%.*s`", LIT(name_token.string)); - } - } else { - gbString type_str = type_to_string(first_type); - error(name_token, "`using` cannot be applied to the field `%.*s` of type `%s`", LIT(name_token.string), type_str); - gb_string_free(type_str); - continue; - } - } - - populate_using_entity_map(c, node, type, &entity_map); - } - } - - // for_array(decl_index, params) { - // check_struct_field_decl(c, params[decl_index], &fields, &entity_map, node, context, context == "struct"); - // } - - - return fields; -} - - -// TODO(bill): Cleanup struct field reordering -// TODO(bill): Inline sorting procedure? -gb_global gbAllocator __checker_allocator = {}; - -GB_COMPARE_PROC(cmp_reorder_struct_fields) { - // Rule: - // `using` over non-`using` - // Biggest to smallest alignment - // if same alignment: biggest to smallest size - // if same size: order by source order - Entity *x = *(Entity **)a; - Entity *y = *(Entity **)b; - GB_ASSERT(x != nullptr); - GB_ASSERT(y != nullptr); - GB_ASSERT(x->kind == Entity_Variable); - GB_ASSERT(y->kind == Entity_Variable); - bool xu = (x->flags & EntityFlag_Using) != 0; - bool yu = (y->flags & EntityFlag_Using) != 0; - i64 xa = type_align_of(__checker_allocator, x->type); - i64 ya = type_align_of(__checker_allocator, y->type); - i64 xs = type_size_of(__checker_allocator, x->type); - i64 ys = type_size_of(__checker_allocator, y->type); - - if (xu != yu) { - return xu ? -1 : +1; - } - - if (xa != ya) { - return xa > ya ? -1 : xa < ya; - } - if (xs != ys) { - return xs > ys ? -1 : xs < ys; - } - i32 diff = x->Variable.field_index - y->Variable.field_index; - return diff < 0 ? -1 : diff > 0; -} - -Entity *make_names_field_for_struct(Checker *c, Scope *scope) { - Entity *e = make_entity_field(c->allocator, scope, - make_token_ident(str_lit("names")), t_string_slice, false, 0); - e->Variable.is_immutable = true; - e->flags |= EntityFlag_TypeField; - return e; -} - -bool check_custom_align(Checker *c, AstNode *node, i64 *align_) { - GB_ASSERT(align_ != nullptr); - Operand o = {}; - check_expr(c, &o, node); - if (o.mode != Addressing_Constant) { - if (o.mode != Addressing_Invalid) { - error(node, "#align must be a constant"); - } - return false; - } - - Type *type = base_type(o.type); - if (is_type_untyped(type) || is_type_integer(type)) { - if (o.value.kind == ExactValue_Integer) { - i64 align = i128_to_i64(o.value.value_integer); - if (align < 1 || !gb_is_power_of_two(align)) { - error(node, "#align must be a power of 2, got %lld", align); - return false; - } - - // NOTE(bill): Success!!! - i64 custom_align = gb_clamp(align, 1, build_context.max_align); - if (custom_align < align) { - warning(node, "Custom alignment has been clamped to %lld from %lld", align, custom_align); - } - *align_ = custom_align; - return true; - } - } - - error(node, "#align must be an integer"); - return false; -} - - -Entity *find_polymorphic_struct_entity(Checker *c, Type *original_type, isize param_count, Array<Operand> ordered_operands) { - auto *found_gen_types = map_get(&c->info.gen_types, hash_pointer(original_type)); - - if (found_gen_types != nullptr) { - for_array(i, *found_gen_types) { - Entity *e = (*found_gen_types)[i]; - Type *t = base_type(e->type); - TypeTuple *tuple = &t->Struct.polymorphic_params->Tuple; - bool ok = true; - GB_ASSERT(param_count == tuple->variables.count); - for (isize j = 0; j < param_count; j++) { - Entity *p = tuple->variables[j]; - Operand o = ordered_operands[j]; - if (p->kind == Entity_TypeName) { - if (is_type_polymorphic(o.type)) { - // NOTE(bill): Do not add polymorphic version to the gen_types - ok = false; - } - if (!are_types_identical(o.type, p->type)) { - ok = false; - } - } else if (p->kind == Entity_Constant) { - if (!are_types_identical(o.type, p->type)) { - ok = false; - } - if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) { - ok = false; - } - } else { - GB_PANIC("Unknown entity kind"); - } - } - if (ok) { - return e; - } - } - } - return nullptr; -} - - -void add_polymorphic_struct_entity(Checker *c, AstNode *node, Type *named_type, Type *original_type) { - GB_ASSERT(is_type_named(named_type)); - gbAllocator a = heap_allocator(); - Scope *s = c->context.scope->parent; - - Entity *e = nullptr; - { - Token token = ast_node_token(node); - token.kind = Token_String; - token.string = named_type->Named.name; - - AstNode *node = gb_alloc_item(a, AstNode); - node->kind = AstNode_Ident; - node->Ident.token = token; - - e = make_entity_type_name(a, s, token, named_type); - add_entity_use(c, node, e); - } - - named_type->Named.type_name = e; - - auto *found_gen_types = map_get(&c->info.gen_types, hash_pointer(original_type)); - if (found_gen_types) { - array_add(found_gen_types, e); - } else { - Array<Entity *> array = {}; - array_init(&array, heap_allocator()); - array_add(&array, e); - map_set(&c->info.gen_types, hash_pointer(original_type), array); - } -} - -void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Operand> *poly_operands, Type *named_type = nullptr, Type *original_type_for_poly = nullptr) { - GB_ASSERT(is_type_struct(struct_type)); - ast_node(st, StructType, node); - - String context = str_lit("struct"); - - isize min_field_count = 0; - for_array(field_index, st->fields) { - AstNode *field = st->fields[field_index]; - switch (field->kind) { - case_ast_node(f, ValueDecl, field); - min_field_count += f->names.count; - case_end; - } - } - struct_type->Struct.names = make_names_field_for_struct(c, c->context.scope); - - if (st->is_raw_union) { - struct_type->Struct.is_raw_union = true; - context = str_lit("struct #raw_union"); - } - - Type *polymorphic_params = nullptr; - bool is_polymorphic = false; - bool can_check_fields = true; - bool is_poly_specialized = false; - - if (st->polymorphic_params != nullptr) { - ast_node(field_list, FieldList, st->polymorphic_params); - Array<AstNode *> params = field_list->list; - if (params.count != 0) { - isize variable_count = 0; - for_array(i, params) { - AstNode *field = params[i]; - if (ast_node_expect(field, AstNode_Field)) { - ast_node(f, Field, field); - variable_count += gb_max(f->names.count, 1); - } - } - - Array<Entity *> entities = {}; - array_init(&entities, c->allocator, variable_count); - - for_array(i, params) { - AstNode *param = params[i]; - if (param->kind != AstNode_Field) { - continue; - } - ast_node(p, Field, param); - AstNode *type_expr = p->type; - Type *type = nullptr; - bool is_type_param = false; - bool is_type_polymorphic_type = false; - if (type_expr == nullptr) { - error(param, "Expected a type for this parameter"); - continue; - } - if (type_expr->kind == AstNode_Ellipsis) { - type_expr = type_expr->Ellipsis.expr; - error(param, "A polymorphic parameter cannot be variadic"); - } - if (type_expr->kind == AstNode_TypeType) { - is_type_param = true; - Type *specialization = nullptr; - if (type_expr->TypeType.specialization != nullptr) { - AstNode *s = type_expr->TypeType.specialization; - specialization = check_type(c, s); - if (false && !is_type_polymorphic_struct(specialization)) { - gbString str = type_to_string(specialization); - defer (gb_string_free(str)); - error(s, "Expected a polymorphic struct, got %s", str); - specialization = nullptr; - } - } - type = make_type_generic(c->allocator, 0, str_lit(""), specialization); - } else { - type = check_type(c, type_expr); - if (is_type_polymorphic(type)) { - is_type_polymorphic_type = true; - } - } - - if (type == nullptr) { - error(params[i], "Invalid parameter type"); - type = t_invalid; - } - if (is_type_untyped(type)) { - if (is_type_untyped_undef(type)) { - error(params[i], "Cannot determine parameter type from ---"); - } else { - error(params[i], "Cannot determine parameter type from a nil"); - } - type = t_invalid; - } - - if (is_type_polymorphic_type) { - gbString str = type_to_string(type); - error(params[i], "Parameter types cannot be polymorphic, got %s", str); - gb_string_free(str); - type = t_invalid; - } - - if (!is_type_param && !is_type_constant_type(type)) { - gbString str = type_to_string(type); - error(params[i], "A parameter must be a valid constant type, got %s", str); - gb_string_free(str); - } - - Scope *scope = c->context.scope; - for_array(j, p->names) { - AstNode *name = p->names[j]; - if (!ast_node_expect(name, AstNode_Ident)) { - continue; - } - Entity *e = nullptr; - - Token token = name->Ident.token; - - if (poly_operands != nullptr) { - Operand operand = (*poly_operands)[entities.count]; - if (is_type_param) { - GB_ASSERT(operand.mode == Addressing_Type || - operand.mode == Addressing_Invalid); - if (is_type_polymorphic(base_type(operand.type))) { - is_polymorphic = true; - can_check_fields = false; - } - e = make_entity_type_name(c->allocator, scope, token, operand.type); - e->TypeName.is_type_alias = true; - } else { - GB_ASSERT(operand.mode == Addressing_Constant); - e = make_entity_constant(c->allocator, scope, token, operand.type, operand.value); - } - } else { - if (is_type_param) { - e = make_entity_type_name(c->allocator, scope, token, type); - e->TypeName.is_type_alias = true; - } else { - e = make_entity_constant(c->allocator, scope, token, type, empty_exact_value); - } - } - - add_entity(c, scope, name, e); - array_add(&entities, e); - } - } - - if (entities.count > 0) { - Type *tuple = make_type_tuple(c->allocator); - tuple->Tuple.variables = entities; - polymorphic_params = tuple; - } - } - - if (original_type_for_poly != nullptr) { - GB_ASSERT(named_type != nullptr); - add_polymorphic_struct_entity(c, node, named_type, original_type_for_poly); - } - } - - if (!is_polymorphic) { - is_polymorphic = polymorphic_params != nullptr && poly_operands == nullptr; - } - if (poly_operands != nullptr) { - is_poly_specialized = true; - for (isize i = 0; i < poly_operands->count; i++) { - Operand o = (*poly_operands)[i]; - if (is_type_polymorphic(o.type)) { - is_poly_specialized = false; - break; - } - } - } - - struct_type->Struct.scope = c->context.scope; - struct_type->Struct.is_packed = st->is_packed; - struct_type->Struct.is_ordered = st->is_ordered; - struct_type->Struct.polymorphic_params = polymorphic_params; - struct_type->Struct.is_polymorphic = is_polymorphic; - struct_type->Struct.is_poly_specialized = is_poly_specialized; - - Array<Entity *> fields = {}; - - if (!is_polymorphic) { - fields = check_struct_fields(c, node, st->fields, min_field_count, named_type, context); - } - - struct_type->Struct.fields = fields; - struct_type->Struct.fields_in_src_order = fields; - - for_array(i, fields) { - Entity *f = fields[i]; - if (f->kind == Entity_Variable) { - if (f->Variable.default_value.kind == ExactValue_Procedure) { - struct_type->Struct.has_proc_default_values = true; - break; - } - } - } - - - if (!struct_type->Struct.is_raw_union) { - type_set_offsets(c->allocator, struct_type); - - if (!struct_type->failure && !st->is_packed && !st->is_ordered) { - struct_type->failure = false; - struct_type->Struct.are_offsets_set = false; - gb_zero_item(&struct_type->Struct.offsets); - // NOTE(bill): Reorder fields for reduced size/performance - - Array<Entity *> reordered_fields = {}; - array_init_count(&reordered_fields, c->allocator, fields.count); - for_array(i, reordered_fields) { - reordered_fields[i] = struct_type->Struct.fields_in_src_order[i]; - } - - // NOTE(bill): Hacky thing - // TODO(bill): Probably make an inline sorting procedure rather than use global variables - __checker_allocator = c->allocator; - // NOTE(bill): compound literal order must match source not layout - gb_sort_array(reordered_fields.data, fields.count, cmp_reorder_struct_fields); - - for_array(i, fields) { - reordered_fields[i]->Variable.field_index = cast(i32)i; - } - - struct_type->Struct.fields = reordered_fields; - } - - type_set_offsets(c->allocator, struct_type); - } - - - if (st->align != nullptr) { - if (st->is_packed) { - syntax_error(st->align, "`#align` cannot be applied with `#packed`"); - return; - } - i64 custom_align = 1; - if (check_custom_align(c, st->align, &custom_align)) { - struct_type->Struct.custom_align = custom_align; - } - } -} -void check_union_type(Checker *c, Type *union_type, AstNode *node) { - GB_ASSERT(is_type_union(union_type)); - ast_node(ut, UnionType, node); - - isize variant_count = ut->variants.count; - - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - Entity *using_index_expr = nullptr; - - Array<Type *> variants = {}; - array_init(&variants, c->allocator, variant_count); - - union_type->Union.scope = c->context.scope; - - for_array(i, ut->variants) { - AstNode *node = ut->variants[i]; - Type *t = check_type(c, node); - if (t != nullptr && t != t_invalid) { - bool ok = true; - t = default_type(t); - if (is_type_untyped(t) || is_type_empty_union(t)) { - ok = false; - gbString str = type_to_string(t); - error(node, "Invalid variant type in union `%s`", str); - gb_string_free(str); - } else { - for_array(j, variants) { - if (are_types_identical(t, variants[j])) { - ok = false; - gbString str = type_to_string(t); - error(node, "Duplicate variant type `%s`", str); - gb_string_free(str); - break; - } - } - } - if (ok) { - array_add(&variants, t); - } - } - } - - union_type->Union.variants = variants; - - if (ut->align != nullptr) { - i64 custom_align = 1; - if (check_custom_align(c, ut->align, &custom_align)) { - if (variants.count == 0) { - error(ut->align, "An empty union cannot have a custom alignment"); - } else { - union_type->Union.custom_align = custom_align; - } - } - } -} - -void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) { - ast_node(et, EnumType, node); - GB_ASSERT(is_type_enum(enum_type)); - - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - Type *base_type = t_int; - if (et->base_type != nullptr) { - base_type = check_type(c, et->base_type); - } - - if (base_type == nullptr || !(is_type_integer(base_type) || is_type_float(base_type))) { - error(node, "Base type for enumeration must be numeric"); - return; - } - if (is_type_enum(base_type)) { - error(node, "Base type for enumeration cannot be another enumeration"); - return; - } - - // NOTE(bill): Must be up here for the `check_init_constant` system - enum_type->Enum.base_type = base_type; - - Map<Entity *> entity_map = {}; // Key: String - map_init(&entity_map, c->tmp_allocator, 2*(et->fields.count)); - - Array<Entity *> fields = {}; - array_init(&fields, c->allocator, et->fields.count); - - Type *constant_type = enum_type; - if (named_type != nullptr) { - constant_type = named_type; - } - - ExactValue iota = exact_value_i64(-1); - ExactValue min_value = exact_value_i64(0); - ExactValue max_value = exact_value_i64(0); - - for_array(i, et->fields) { - AstNode *field = et->fields[i]; - AstNode *ident = nullptr; - AstNode *init = nullptr; - if (field->kind == AstNode_FieldValue) { - ast_node(fv, FieldValue, field); - if (fv->field == nullptr || fv->field->kind != AstNode_Ident) { - error(field, "An enum field's name must be an identifier"); - continue; - } - ident = fv->field; - init = fv->value; - } else if (field->kind == AstNode_Ident) { - ident = field; - } else { - error(field, "An enum field's name must be an identifier"); - continue; - } - String name = ident->Ident.token.string; - - if (init != nullptr) { - Operand o = {}; - check_expr(c, &o, init); - if (o.mode != Addressing_Constant) { - error(init, "Enumeration value must be a constant"); - o.mode = Addressing_Invalid; - } - if (o.mode != Addressing_Invalid) { - check_assignment(c, &o, constant_type, str_lit("enumeration")); - } - if (o.mode != Addressing_Invalid) { - iota = o.value; - } else { - iota = exact_binary_operator_value(Token_Add, iota, exact_value_i64(1)); - } - } else { - iota = exact_binary_operator_value(Token_Add, iota, exact_value_i64(1)); - } - - - // NOTE(bill): Skip blank identifiers - if (is_blank_ident(name)) { - continue; - } else if (name == "count") { - error(field, "`count` is a reserved identifier for enumerations"); - continue; - } else if (name == "min_value") { - error(field, "`min_value` is a reserved identifier for enumerations"); - continue; - } else if (name == "max_value") { - error(field, "`max_value` is a reserved identifier for enumerations"); - continue; - } else if (name == "names") { - error(field, "`names` is a reserved identifier for enumerations"); - continue; - }/* else if (name == "base_type") { - error(field, "`base_type` is a reserved identifier for enumerations"); - continue; - } */ - - if (compare_exact_values(Token_Gt, min_value, iota)) { - min_value = iota; - } - if (compare_exact_values(Token_Lt, max_value, iota)) { - max_value = iota; - } - - Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident.token, constant_type, iota); - e->identifier = ident; - e->flags |= EntityFlag_Visited; - - HashKey key = hash_string(name); - if (map_get(&entity_map, key) != nullptr) { - error(ident, "`%.*s` is already declared in this enumeration", LIT(name)); - } else { - map_set(&entity_map, key, e); - add_entity(c, c->context.scope, nullptr, e); - array_add(&fields, e); - add_entity_use(c, field, e); - } - } - GB_ASSERT(fields.count <= et->fields.count); - - - enum_type->Enum.fields = fields.data; - enum_type->Enum.field_count = cast(i32)fields.count; - - enum_type->Enum.count = make_entity_constant(c->allocator, c->context.scope, - make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count)); - enum_type->Enum.min_value = make_entity_constant(c->allocator, c->context.scope, - make_token_ident(str_lit("min_value")), constant_type, min_value); - enum_type->Enum.max_value = make_entity_constant(c->allocator, c->context.scope, - make_token_ident(str_lit("max_value")), constant_type, max_value); - - enum_type->Enum.names = make_names_field_for_struct(c, c->context.scope); -} - - -void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) { - ast_node(bft, BitFieldType, node); - GB_ASSERT(is_type_bit_field(bit_field_type)); - - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - Map<Entity *> entity_map = {}; // Key: String - map_init(&entity_map, c->tmp_allocator, 2*(bft->fields.count)); - - isize field_count = 0; - Entity **fields = gb_alloc_array(c->allocator, Entity *, bft->fields.count); - u32 * sizes = gb_alloc_array(c->allocator, u32, bft->fields.count); - u32 * offsets = gb_alloc_array(c->allocator, u32, bft->fields.count); - - u32 curr_offset = 0; - for_array(i, bft->fields) { - AstNode *field = bft->fields[i]; - GB_ASSERT(field->kind == AstNode_FieldValue); - AstNode *ident = field->FieldValue.field; - AstNode *value = field->FieldValue.value; - - if (ident->kind != AstNode_Ident) { - error(field, "A bit field value's name must be an identifier"); - continue; - } - String name = ident->Ident.token.string; - - Operand o = {}; - check_expr(c, &o, value); - if (o.mode != Addressing_Constant) { - error(value, "Bit field bit size must be a constant"); - continue; - } - ExactValue v = exact_value_to_integer(o.value); - if (v.kind != ExactValue_Integer) { - error(value, "Bit field bit size must be a constant integer"); - continue; - } - i64 bits = i128_to_i64(v.value_integer); - if (bits < 0 || bits > 128) { - error(value, "Bit field's bit size must be within the range 1..<128, got %lld", cast(long long)bits); - continue; - } - - Type *value_type = make_type_bit_field_value(c->allocator, cast(i32)bits); - Entity *e = make_entity_variable(c->allocator, bit_field_type->BitField.scope, ident->Ident.token, value_type, false); - e->identifier = ident; - e->flags |= EntityFlag_BitFieldValue; - - HashKey key = hash_string(name); - if (!is_blank_ident(name) && - map_get(&entity_map, key) != nullptr) { - error(ident, "`%.*s` is already declared in this bit field", LIT(name)); - } else { - map_set(&entity_map, key, e); - add_entity(c, c->context.scope, nullptr, e); - add_entity_use(c, field, e); - - fields [field_count] = e; - offsets[field_count] = curr_offset; - sizes [field_count] = cast(i32)bits; - field_count++; - - curr_offset += cast(i32)bits; - } - } - GB_ASSERT(field_count <= bft->fields.count); - - bit_field_type->BitField.fields = fields; - bit_field_type->BitField.field_count = cast(i32)field_count; - bit_field_type->BitField.sizes = sizes; - bit_field_type->BitField.offsets = offsets; - - - if (bft->align != nullptr) { - i64 custom_align = 1; - if (check_custom_align(c, bft->align, &custom_align)) { - bit_field_type->BitField.custom_align = custom_align; - } - } -} - - -bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type) { - if (type == nullptr || - type == t_invalid) { - return true; - } - - Type *t = base_type(type); - Type *s = base_type(specialization); - if (t->kind != s->kind) { - return false; - } - // gb_printf_err("#1 %s %s\n", type_to_string(type), type_to_string(specialization)); - if (t->kind == Type_Struct) { - if (t->Struct.polymorphic_parent == specialization) { - return true; - } - - if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent && - s->Struct.polymorphic_params != nullptr && - t->Struct.polymorphic_params != nullptr) { - - TypeTuple *s_tuple = &s->Struct.polymorphic_params->Tuple; - TypeTuple *t_tuple = &t->Struct.polymorphic_params->Tuple; - GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count); - for_array(i, s_tuple->variables) { - Entity *s_e = s_tuple->variables[i]; - Entity *t_e = t_tuple->variables[i]; - Type *st = s_e->type; - Type *tt = t_e->type; - bool ok = is_polymorphic_type_assignable(c, st, tt, true, modify_type); - } - - if (modify_type) { - // NOTE(bill): This is needed in order to change the actual type but still have the types defined within it - gb_memmove(specialization, type, gb_size_of(Type)); - } - - return true; - } - } - - if (specialization->kind == Type_Named && - type->kind != Type_Named) { - return false; - } - if (is_polymorphic_type_assignable(c, base_type(specialization), base_type(type), compound, modify_type)) { - return true; - } - - return false; -} bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type) { Operand o = {Addressing_Value}; @@ -2064,763 +883,6 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c return false; } -Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) { - bool modify_type = !c->context.no_polymorphic_errors; - if (!is_operand_value(operand)) { - if (modify_type) { - error(operand.expr, "Cannot determine polymorphic type from parameter"); - } - return t_invalid; - } - if (is_polymorphic_type_assignable(c, poly_type, operand.type, false, modify_type)) { - return poly_type; - } - if (modify_type) { - gbString pts = type_to_string(poly_type); - gbString ots = type_to_string(operand.type); - defer (gb_string_free(pts)); - defer (gb_string_free(ots)); - error(operand.expr, "Cannot determine polymorphic type from parameter: `%s` to `%s`", ots, pts); - } - return t_invalid; -} - - -Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, isize *specialization_count_, Array<Operand> *operands) { - if (_params == nullptr) { - return nullptr; - } - - bool allow_polymorphic_types = c->context.allow_polymorphic_types; - - bool success = true; - ast_node(field_list, FieldList, _params); - Array<AstNode *> params = field_list->list; - - if (params.count == 0) { - if (success_) *success_ = success; - return nullptr; - } - - - - isize variable_count = 0; - for_array(i, params) { - AstNode *field = params[i]; - if (ast_node_expect(field, AstNode_Field)) { - ast_node(f, Field, field); - variable_count += gb_max(f->names.count, 1); - } - } - isize min_variable_count = variable_count; - for (isize i = params.count-1; i >= 0; i--) { - AstNode *field = params[i]; - if (field->kind == AstNode_Field) { - ast_node(f, Field, field); - if (f->default_value == nullptr) { - break; - } - min_variable_count--; - } - } - - - bool is_variadic = false; - bool is_c_vararg = false; - Array<Entity *> variables = {}; - array_init(&variables, c->allocator, variable_count); - for_array(i, params) { - AstNode *param = params[i]; - if (param->kind != AstNode_Field) { - continue; - } - ast_node(p, Field, param); - AstNode *type_expr = p->type; - Type *type = nullptr; - AstNode *default_value = unparen_expr(p->default_value); - ExactValue value = {}; - bool default_is_nil = false; - bool default_is_location = false; - bool is_type_param = false; - bool is_type_polymorphic_type = false; - bool detemine_type_from_operand = false; - Type *specialization = nullptr; - - - if (type_expr == nullptr) { - if (default_value->kind == AstNode_BasicDirective && - default_value->BasicDirective.name == "caller_location") { - init_preload(c); - default_is_location = true; - type = t_source_code_location; - } else { - Operand o = {}; - check_expr_or_type(c, &o, default_value); - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - if (default_value->kind == AstNode_ProcLit) { - value = exact_value_procedure(default_value); - } else { - Entity *e = nullptr; - if (o.mode == Addressing_Value && is_type_proc(o.type)) { - Operand x = {}; - if (default_value->kind == AstNode_Ident) { - e = check_ident(c, &x, default_value, nullptr, nullptr, false); - } else if (default_value->kind == AstNode_SelectorExpr) { - e = check_selector(c, &x, default_value, nullptr); - } - } - - if (e != nullptr && e->kind == Entity_Procedure) { - value = exact_value_procedure(e->identifier); - add_entity_use(c, e->identifier, e); - } else { - error(default_value, "Default parameter must be a constant"); - } - } - } else { - value = o.value; - } - - type = default_type(o.type); - } - } else { - if (type_expr->kind == AstNode_Ellipsis) { - type_expr = type_expr->Ellipsis.expr; - if (i+1 == params.count) { - is_variadic = true; - } else { - error(param, "Invalid AST: Invalid variadic parameter"); - success = false; - } - } - if (type_expr->kind == AstNode_TypeType) { - ast_node(tt, TypeType, type_expr); - is_type_param = true; - specialization = check_type(c, tt->specialization); - if (specialization == t_invalid){ - specialization = nullptr; - } - // if (specialization) { - // if (!is_type_polymorphic(specialization)) { - // gbString str = type_to_string(specialization); - // error(tt->specialization, "Type specialization requires a polymorphic type, got %s", str); - // gb_string_free(str); - // } - // } - - if (operands != nullptr) { - detemine_type_from_operand = true; - type = t_invalid; - } else { - type = make_type_generic(c->allocator, 0, str_lit(""), specialization); - } - } else { - bool prev = c->context.allow_polymorphic_types; - if (operands != nullptr) { - c->context.allow_polymorphic_types = true; - } - type = check_type(c, type_expr); - - c->context.allow_polymorphic_types = prev; - - if (is_type_polymorphic(type)) { - is_type_polymorphic_type = true; - } - } - - if (default_value != nullptr) { - if (type_expr->kind == AstNode_TypeType) { - error(default_value, "A type parameter may not have a default value"); - } else { - Operand o = {}; - if (default_value->kind == AstNode_BasicDirective && - default_value->BasicDirective.name == "caller_location") { - init_preload(c); - default_is_location = true; - o.type = t_source_code_location; - o.mode = Addressing_Value; - } else { - check_expr_with_type_hint(c, &o, default_value, type); - - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - if (default_value->kind == AstNode_ProcLit) { - value = exact_value_procedure(default_value); - } else { - Entity *e = nullptr; - if (o.mode == Addressing_Value && is_type_proc(o.type)) { - Operand x = {}; - if (default_value->kind == AstNode_Ident) { - e = check_ident(c, &x, default_value, nullptr, nullptr, false); - } else if (default_value->kind == AstNode_SelectorExpr) { - e = check_selector(c, &x, default_value, nullptr); - } - } - - if (e != nullptr && e->kind == Entity_Procedure) { - value = exact_value_procedure(e->identifier); - add_entity_use(c, e->identifier, e); - } else { - error(default_value, "Default parameter must be a constant"); - } - } - } else { - value = o.value; - } - } - - check_is_assignable_to(c, &o, type); - } - } - - } - if (type == nullptr) { - error(params[i], "Invalid parameter type"); - type = t_invalid; - } - if (is_type_untyped(type)) { - if (is_type_untyped_undef(type)) { - error(params[i], "Cannot determine parameter type from ---"); - } else { - error(params[i], "Cannot determine parameter type from a nil"); - } - type = t_invalid; - } - if (is_type_empty_union(type)) { - gbString str = type_to_string(type); - error(params[i], "Invalid use of an empty union `%s`", str); - gb_string_free(str); - type = t_invalid; - } - - - if (p->flags&FieldFlag_c_vararg) { - if (p->type == nullptr || - p->type->kind != AstNode_Ellipsis) { - error(params[i], "`#c_vararg` can only be applied to variadic type fields"); - p->flags &= ~FieldFlag_c_vararg; // Remove the flag - } else { - is_c_vararg = true; - } - } - - - for_array(j, p->names) { - AstNode *name = p->names[j]; - if (!ast_node_expect(name, AstNode_Ident)) { - continue; - } - - Entity *param = nullptr; - if (is_type_param) { - if (operands != nullptr) { - Operand o = (*operands)[variables.count]; - if (o.mode == Addressing_Type) { - type = o.type; - } else { - if (!c->context.no_polymorphic_errors) { - error(o.expr, "Expected a type to assign to the type parameter"); - } - success = false; - type = t_invalid; - } - if (is_type_polymorphic(type)) { - gbString str = type_to_string(type); - error(o.expr, "Cannot pass polymorphic type as a parameter, got `%s`", str); - gb_string_free(str); - success = false; - type = t_invalid; - } - bool modify_type = !c->context.no_polymorphic_errors; - - if (specialization != nullptr && !check_type_specialization_to(c, specialization, type, false, modify_type)) { - if (!c->context.no_polymorphic_errors) { - gbString t = type_to_string(type); - gbString s = type_to_string(specialization); - error(o.expr, "Cannot convert type `%s` to the specialization `%s`", t, s); - gb_string_free(s); - gb_string_free(t); - } - success = false; - type = t_invalid; - } - } - param = make_entity_type_name(c->allocator, scope, name->Ident.token, type); - param->TypeName.is_type_alias = true; - } else { - if (operands != nullptr && is_type_polymorphic_type) { - Operand op = (*operands)[variables.count]; - type = determine_type_from_polymorphic(c, type, op); - if (type == t_invalid) { - success = false; - } else if (!c->context.no_polymorphic_errors) { - // NOTE(bill): The type should be determined now and thus, no need to determine the type any more - is_type_polymorphic_type = false; - // is_type_polymorphic_type = is_type_polymorphic(base_type(type)); - } - } - - if (p->flags&FieldFlag_no_alias) { - if (!is_type_pointer(type)) { - error(params[i], "`#no_alias` can only be applied to fields of pointer type"); - p->flags &= ~FieldFlag_no_alias; // Remove the flag - } - } - - param = make_entity_param(c->allocator, scope, name->Ident.token, type, - (p->flags&FieldFlag_using) != 0, false); - param->Variable.default_value = value; - param->Variable.default_is_nil = default_is_nil; - param->Variable.default_is_location = default_is_location; - - } - if (p->flags&FieldFlag_no_alias) { - param->flags |= EntityFlag_NoAlias; - } - - add_entity(c, scope, name, param); - array_add(&variables, param); - } - } - - - if (is_variadic) { - GB_ASSERT(params.count > 0); - // NOTE(bill): Change last variadic parameter to be a slice - // Custom Calling convention for variadic parameters - Entity *end = variables[variable_count-1]; - end->type = make_type_slice(c->allocator, end->type); - end->flags |= EntityFlag_Ellipsis; - if (is_c_vararg) { - end->flags |= EntityFlag_CVarArg; - } - } - - isize specialization_count = 0; - if (scope != nullptr) { - for_array(i, scope->elements.entries) { - Entity *e = scope->elements.entries[i].value; - if (e->kind == Entity_TypeName) { - Type *t = e->type; - if (t->kind == Type_Generic && - t->Generic.specialized != nullptr) { - specialization_count += 1; - } - } - } - } - - Type *tuple = make_type_tuple(c->allocator); - tuple->Tuple.variables = variables; - - if (success_) *success_ = success; - if (specialization_count_) *specialization_count_ = specialization_count; - if (is_variadic_) *is_variadic_ = is_variadic; - - return tuple; -} - -Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { - if (_results == nullptr) { - return nullptr; - } - ast_node(field_list, FieldList, _results); - Array<AstNode *> results = field_list->list; - - if (results.count == 0) { - return nullptr; - } - Type *tuple = make_type_tuple(c->allocator); - - isize variable_count = 0; - for_array(i, results) { - AstNode *field = results[i]; - if (ast_node_expect(field, AstNode_Field)) { - ast_node(f, Field, field); - variable_count += gb_max(f->names.count, 1); - } - } - - Array<Entity *> variables = {}; - array_init(&variables, c->allocator, variable_count); - for_array(i, results) { - ast_node(field, Field, results[i]); - AstNode *default_value = unparen_expr(field->default_value); - ExactValue value = {}; - bool default_is_nil = false; - - Type *type = nullptr; - if (field->type == nullptr) { - Operand o = {}; - check_expr(c, &o, default_value); - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - error(default_value, "Default parameter must be a constant"); - } else { - value = o.value; - } - - type = default_type(o.type); - } else { - type = check_type(c, field->type); - - if (default_value != nullptr) { - Operand o = {}; - check_expr_with_type_hint(c, &o, default_value, type); - - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - error(default_value, "Default parameter must be a constant"); - } else { - value = o.value; - } - check_is_assignable_to(c, &o, type); - } - } - - if (type == nullptr) { - error(results[i], "Invalid parameter type"); - type = t_invalid; - } - if (is_type_untyped(type)) { - error(results[i], "Cannot determine parameter type from a nil"); - type = t_invalid; - } - - - if (field->names.count == 0) { - Token token = ast_node_token(field->type); - token.string = str_lit(""); - Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); - param->Variable.default_value = value; - param->Variable.default_is_nil = default_is_nil; - array_add(&variables, param); - } else { - for_array(j, field->names) { - Token token = ast_node_token(results[i]); - if (field->type != nullptr) { - token = ast_node_token(field->type); - } - token.string = str_lit(""); - - AstNode *name = field->names[j]; - if (name->kind != AstNode_Ident) { - error(name, "Expected an identifer for as the field name"); - } else { - token = name->Ident.token; - } - - Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); - param->Variable.default_value = value; - param->Variable.default_is_nil = default_is_nil; - array_add(&variables, param); - } - } - } - - for_array(i, variables) { - String x = variables[i]->token.string; - if (x.len == 0 || is_blank_ident(x)) { - continue; - } - for (isize j = i+1; j < variables.count; j++) { - String y = variables[j]->token.string; - if (y.len == 0 || is_blank_ident(y)) { - continue; - } - if (x == y) { - error(variables[j]->token, "Duplicate return value name `%.*s`", LIT(y)); - } - } - } - - tuple->Tuple.variables = variables; - - return tuple; -} - -Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { - Type *new_type = original_type; - - if (build_context.ODIN_ARCH == "x86") { - return new_type; - } - - if (build_context.ODIN_OS == "windows") { - // NOTE(bill): Changing the passing parameter value type is to match C's ABI - // IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment - // SEE: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx - Type *bt = core_type(original_type); - switch (bt->kind) { - // Okay to pass by value (usually) - // Especially the only Odin types - case Type_Basic: { - i64 sz = bt->Basic.size; - if (sz > 8 && build_context.word_size < 8) { - new_type = make_type_pointer(a, original_type); - } - break; - } - case Type_Pointer: break; - case Type_Proc: break; // NOTE(bill): Just a pointer - - // Odin only types - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - break; - - // Odin specific - case Type_Array: - case Type_Vector: - // Could be in C too - case Type_Struct: { - i64 align = type_align_of(a, original_type); - i64 size = type_size_of(a, original_type); - switch (8*size) { - case 8: new_type = t_u8; break; - case 16: new_type = t_u16; break; - case 32: new_type = t_u32; break; - case 64: new_type = t_u64; break; - default: - new_type = make_type_pointer(a, original_type); - break; - } - - break; - } - } - } else if (build_context.ODIN_OS == "linux" || - build_context.ODIN_OS == "osx") { - Type *bt = core_type(original_type); - switch (bt->kind) { - // Okay to pass by value (usually) - // Especially the only Odin types - case Type_Basic: { - i64 sz = bt->Basic.size; - if (sz > 8 && build_context.word_size < 8) { - new_type = make_type_pointer(a, original_type); - } - - break; - } - case Type_Pointer: break; - case Type_Proc: break; // NOTE(bill): Just a pointer - - // Odin only types - case Type_Slice: - case Type_DynamicArray: - case Type_Map: - break; - - // Odin specific - case Type_Array: - case Type_Vector: - // Could be in C too - case Type_Struct: { - i64 align = type_align_of(a, original_type); - i64 size = type_size_of(a, original_type); - if (8*size > 16) { - new_type = make_type_pointer(a, original_type); - } - - break; - } - } - } else { - // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for - // their architectures - } - - return new_type; -} - -Type *reduce_tuple_to_single_type(Type *original_type) { - if (original_type != nullptr) { - Type *t = core_type(original_type); - if (t->kind == Type_Tuple && t->Tuple.variables.count == 1) { - return t->Tuple.variables[0]->type; - } - } - return original_type; -} - -Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { - Type *new_type = original_type; - if (new_type == nullptr) { - return nullptr; - } - GB_ASSERT(is_type_tuple(original_type)); - - - - if (build_context.ODIN_OS == "windows") { - Type *bt = core_type(reduce_tuple_to_single_type(original_type)); - // NOTE(bill): This is just reversed engineered from LLVM IR output - switch (bt->kind) { - // Okay to pass by value - // Especially the only Odin types - case Type_Pointer: break; - case Type_Proc: break; // NOTE(bill): Just a pointer - case Type_Basic: break; - - - default: { - i64 align = type_align_of(a, original_type); - i64 size = type_size_of(a, original_type); - switch (8*size) { -#if 1 - case 8: new_type = t_u8; break; - case 16: new_type = t_u16; break; - case 32: new_type = t_u32; break; - case 64: new_type = t_u64; break; -#endif - } - - break; - } - } - } else if (build_context.ODIN_OS == "linux") { - - } else { - // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for - // their architectures - } - - if (new_type != original_type) { - Type *tuple = make_type_tuple(a); - Array<Entity *> variables = {}; - array_init(&variables, a, 1); - array_add(&variables, make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false)); - tuple->Tuple.variables = variables; - new_type = tuple; - } - - - // return reduce_tuple_to_single_type(new_type); - return new_type; -} - -bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type) { - if (abi_return_type == nullptr) { - return false; - } - switch (cc) { - case ProcCC_Odin: - case ProcCC_Contextless: - return false; - } - - - if (build_context.ODIN_OS == "windows") { - i64 size = 8*type_size_of(a, abi_return_type); - switch (size) { - case 0: - case 8: - case 16: - case 32: - case 64: - return false; - default: - return true; - } - } - return false; -} - -// NOTE(bill): `operands` is for generating non generic procedure type -bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands) { - ast_node(pt, ProcType, proc_type_node); - - if (c->context.polymorphic_scope == nullptr && c->context.allow_polymorphic_types) { - c->context.polymorphic_scope = c->context.scope; - } - - bool variadic = false; - bool success = true; - isize specialization_count = 0; - Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, &specialization_count, operands); - Type *results = check_get_results(c, c->context.scope, pt->results); - - - isize param_count = 0; - isize result_count = 0; - if (params) param_count = params ->Tuple.variables.count; - if (results) result_count = results->Tuple.variables.count; - - if (param_count > 0) { - for_array(i, params->Tuple.variables) { - Entity *param = params->Tuple.variables[i]; - if (param->kind == Entity_Variable && param->Variable.default_value.kind == ExactValue_Procedure) { - type->Proc.has_proc_default_values = true; - break; - } - } - } - - type->Proc.node = proc_type_node; - type->Proc.scope = c->context.scope; - type->Proc.params = params; - type->Proc.param_count = cast(i32)param_count; - type->Proc.results = results; - type->Proc.result_count = cast(i32)result_count; - type->Proc.variadic = variadic; - type->Proc.calling_convention = pt->calling_convention; - type->Proc.is_polymorphic = pt->generic; - type->Proc.specialization_count = specialization_count; - - if (param_count > 0) { - Entity *end = params->Tuple.variables[param_count-1]; - if (end->flags&EntityFlag_CVarArg) { - if (pt->calling_convention == ProcCC_Odin) { - error(end->token, "Odin calling convention does not support #c_vararg"); - } else if (pt->calling_convention == ProcCC_Contextless) { - error(end->token, "Odin's contextless calling convention does not support #c_vararg"); - } else if (pt->calling_convention == ProcCC_Fast) { - error(end->token, "Fast calling convention does not support #c_vararg"); - } else { - type->Proc.c_vararg = true; - } - } - } - - - bool is_polymorphic = false; - for (isize i = 0; i < param_count; i++) { - Entity *e = params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - is_polymorphic = true; - break; - } else if (is_type_polymorphic(e->type)) { - is_polymorphic = true; - break; - } - } - type->Proc.is_polymorphic = is_polymorphic; - - - type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count); - for (isize i = 0; i < param_count; i++) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind == Entity_Variable) { - Type *original_type = e->type; - Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type); - type->Proc.abi_compat_params[i] = new_type; - } - } - - // NOTE(bill): The types are the same - type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results); - type->Proc.return_by_pointer = abi_compat_return_by_value(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type); - - return success; -} - Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) { GB_ASSERT(n->kind == AstNode_Ident); @@ -2992,442 +1054,6 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * return e; } -i64 check_array_count(Checker *c, AstNode *e) { - if (e == nullptr) { - return 0; - } - Operand o = {}; - if (e->kind == AstNode_UnaryExpr && - e->UnaryExpr.op.kind == Token_Ellipsis) { - return -1; - } - - check_expr(c, &o, e); - if (o.mode != Addressing_Constant) { - if (o.mode != Addressing_Invalid) { - error(e, "Array count must be a constant"); - } - return 0; - } - Type *type = base_type(o.type); - if (is_type_untyped(type) || is_type_integer(type)) { - if (o.value.kind == ExactValue_Integer) { - i64 count = i128_to_i64(o.value.value_integer); - if (count >= 0) { - return count; - } - error(e, "Invalid negative array count %lld", cast(long long)count); - return 0; - } - } - - error(e, "Array count must be an integer"); - return 0; -} - -Type *make_optional_ok_type(gbAllocator a, Type *value) { - bool typed = true; - Type *t = make_type_tuple(a); - array_init(&t->Tuple.variables, a, 2); - array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, value, false, 0)); - array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1)); - return t; -} - -void generate_map_entry_type(gbAllocator a, Type *type) { - GB_ASSERT(type->kind == Type_Map); - if (type->Map.entry_type != nullptr) return; - - // NOTE(bill): The preload types may have not been set yet - GB_ASSERT(t_map_key != nullptr); - - Type *entry_type = make_type_struct(a); - - /* - struct { - hash: __MapKey; - next: int; - key: Key; - value: Value; - } - */ - AstNode *dummy_node = gb_alloc_item(a, AstNode); - dummy_node->kind = AstNode_Invalid; - Scope *s = create_scope(universal_scope, a); - - isize field_count = 3; - Array<Entity *> fields = {}; - array_init(&fields, a, 3); - array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("key")), t_map_key, false, 0)); - array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("next")), t_int, false, 1)); - array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("value")), type->Map.value, false, 2)); - - - entry_type->Struct.is_ordered = true; - entry_type->Struct.fields = fields; - entry_type->Struct.fields_in_src_order = fields; - - // type_set_offsets(a, entry_type); - type->Map.entry_type = entry_type; -} - -void generate_map_internal_types(gbAllocator a, Type *type) { - GB_ASSERT(type->kind == Type_Map); - generate_map_entry_type(a, type); - if (type->Map.generated_struct_type != nullptr) return; - Type *key = type->Map.key; - Type *value = type->Map.value; - GB_ASSERT(key != nullptr); - GB_ASSERT(value != nullptr); - - Type *generated_struct_type = make_type_struct(a); - - /* - struct { - hashes: [dynamic]int; - entries: [dynamic]EntryType; - } - */ - AstNode *dummy_node = gb_alloc_item(a, AstNode); - dummy_node->kind = AstNode_Invalid; - Scope *s = create_scope(universal_scope, a); - - Type *hashes_type = make_type_dynamic_array(a, t_int); - Type *entries_type = make_type_dynamic_array(a, type->Map.entry_type); - - - Array<Entity *> fields = {}; - array_init(&fields, a, 2); - array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("hashes")), hashes_type, false, 0)); - array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("entries")), entries_type, false, 1)); - - generated_struct_type->Struct.is_ordered = true; - generated_struct_type->Struct.fields = fields; - generated_struct_type->Struct.fields_in_src_order = fields; - - type_set_offsets(a, generated_struct_type); - type->Map.generated_struct_type = generated_struct_type; - type->Map.lookup_result_type = make_optional_ok_type(a, value); -} - -void check_map_type(Checker *c, Type *type, AstNode *node) { - GB_ASSERT(type->kind == Type_Map); - ast_node(mt, MapType, node); - - Type *key = check_type(c, mt->key); - Type *value = check_type(c, mt->value); - - if (!is_type_valid_for_keys(key)) { - if (is_type_boolean(key)) { - error(node, "A boolean cannot be used as a key for a map, use an array instead for this case"); - } else { - gbString str = type_to_string(key); - error(node, "Invalid type of a key for a map, got `%s`", str); - gb_string_free(str); - } - } - - type->Map.key = key; - type->Map.value = value; - - - init_preload(c); - generate_map_internal_types(c->allocator, type); - - // error(node, "`map` types are not yet implemented"); -} - -bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) { - GB_ASSERT_NOT_NULL(type); - if (e == nullptr) { - *type = t_invalid; - return true; - } - - switch (e->kind) { - case_ast_node(i, Ident, e); - - Operand o = {}; - check_ident(c, &o, e, named_type, nullptr, false); - - gbString err_str; - switch (o.mode) { - case Addressing_Invalid: - break; - case Addressing_Type: - *type = o.type; - return true; - - case Addressing_NoValue: - err_str = expr_to_string(e); - error(e, "`%s` used as a type", err_str); - gb_string_free(err_str); - break; - - default: - err_str = expr_to_string(e); - error(e, "`%s` used as a type when not a type", err_str); - gb_string_free(err_str); - break; - } - case_end; - - case_ast_node(ht, HelperType, e); - return check_type_internal(c, ht->type, type, named_type); - case_end; - - case_ast_node(pt, PolyType, e); - AstNode *ident = pt->type; - if (ident->kind != AstNode_Ident) { - error(ident, "Expected an identifier after the $"); - *type = t_invalid; - return false; - } - - Token token = ident->Ident.token; - Type *specific = nullptr; - if (pt->specialization != nullptr) { - AstNode *s = pt->specialization; - specific = check_type(c, s); - if (false && !is_type_polymorphic_struct(specific)) { - gbString str = type_to_string(specific); - error(s, "Expected a polymorphic struct, got %s", str); - gb_string_free(str); - specific = nullptr; - } - } - Type *t = make_type_generic(c->allocator, 0, token.string, specific); - if (c->context.allow_polymorphic_types) { - Scope *ps = c->context.polymorphic_scope; - Scope *s = c->context.scope; - Scope *entity_scope = s; - if (ps != nullptr && ps != s) { - GB_ASSERT(is_scope_an_ancestor(ps, s) >= 0); - entity_scope = ps; - } - Entity *e = make_entity_type_name(c->allocator, entity_scope, token, t); - e->TypeName.is_type_alias = true; - add_entity(c, ps, ident, e); - add_entity(c, s, ident, e); - } else { - error(ident, "Invalid use of a polymorphic type `$%.*s`", LIT(token.string)); - *type = t_invalid; - return false; - } - *type = t; - return true; - case_end; - - case_ast_node(se, SelectorExpr, e); - Operand o = {}; - check_selector(c, &o, e, nullptr); - - gbString err_str; - switch (o.mode) { - case Addressing_Invalid: - break; - case Addressing_Type: - GB_ASSERT(o.type != nullptr); - *type = o.type; - return true; - case Addressing_NoValue: - err_str = expr_to_string(e); - error(e, "`%s` used as a type", err_str); - gb_string_free(err_str); - break; - default: - err_str = expr_to_string(e); - error(e, "`%s` is not a type", err_str); - gb_string_free(err_str); - break; - } - case_end; - - case_ast_node(pe, ParenExpr, e); - *type = check_type(c, pe->expr, named_type); - return true; - case_end; - - case_ast_node(ue, UnaryExpr, e); - if (ue->op.kind == Token_Pointer) { - *type = make_type_pointer(c->allocator, check_type(c, ue->expr)); - return true; - } /* else if (ue->op.kind == Token_Maybe) { - *type = make_type_maybe(c->allocator, check_type(c, ue->expr)); - return true; - } */ - case_end; - - case_ast_node(pt, PointerType, e); - Type *elem = check_type(c, pt->type); - i64 esz = type_size_of(c->allocator, elem); - *type = make_type_pointer(c->allocator, elem); - return true; - case_end; - - case_ast_node(at, ArrayType, e); - if (at->count != nullptr) { - Type *elem = check_type(c, at->elem, nullptr); - i64 count = check_array_count(c, at->count); - if (count < 0) { - error(at->count, "... can only be used in conjuction with compound literals"); - count = 0; - } - *type = make_type_array(c->allocator, elem, count); - } else { - Type *elem = check_type(c, at->elem); - *type = make_type_slice(c->allocator, elem); - } - return true; - case_end; - - case_ast_node(dat, DynamicArrayType, e); - Type *elem = check_type(c, dat->elem); - *type = make_type_dynamic_array(c->allocator, elem); - return true; - case_end; - - - - case_ast_node(vt, VectorType, e); - Type *elem = check_type(c, vt->elem); - Type *be = base_type(elem); - i64 count = check_array_count(c, vt->count); - if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be) && be->kind != Type_Generic)) { - gbString err_str = type_to_string(elem); - error(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str); - gb_string_free(err_str); - } - *type = make_type_vector(c->allocator, elem, count); - return true; - case_end; - - case_ast_node(st, StructType, e); - *type = make_type_struct(c->allocator); - set_base_type(named_type, *type); - check_open_scope(c, e); - check_struct_type(c, *type, e, nullptr, named_type); - check_close_scope(c); - (*type)->Struct.node = e; - return true; - case_end; - - case_ast_node(ut, UnionType, e); - *type = make_type_union(c->allocator); - set_base_type(named_type, *type); - check_open_scope(c, e); - check_union_type(c, *type, e); - check_close_scope(c); - (*type)->Union.node = e; - return true; - case_end; - - case_ast_node(et, EnumType, e); - *type = make_type_enum(c->allocator); - set_base_type(named_type, *type); - check_open_scope(c, e); - check_enum_type(c, *type, named_type, e); - check_close_scope(c); - (*type)->Enum.node = e; - return true; - case_end; - - case_ast_node(et, BitFieldType, e); - *type = make_type_bit_field(c->allocator); - set_base_type(named_type, *type); - check_open_scope(c, e); - check_bit_field_type(c, *type, e); - check_close_scope(c); - return true; - case_end; - - case_ast_node(pt, ProcType, e); - *type = alloc_type(c->allocator, Type_Proc); - set_base_type(named_type, *type); - check_open_scope(c, e); - check_procedure_type(c, *type, e); - check_close_scope(c); - return true; - case_end; - - case_ast_node(mt, MapType, e); - *type = alloc_type(c->allocator, Type_Map); - set_base_type(named_type, *type); - check_map_type(c, *type, e); - return true; - case_end; - - case_ast_node(ce, CallExpr, e); - Operand o = {}; - check_expr_or_type(c, &o, e); - if (o.mode == Addressing_Type) { - *type = o.type; - return true; - } - case_end; - - case_ast_node(te, TernaryExpr, e); - Operand o = {}; - check_expr_or_type(c, &o, e); - if (o.mode == Addressing_Type) { - *type = o.type; - return true; - } - case_end; - } - - *type = t_invalid; - return false; -} - - - -Type *check_type(Checker *c, AstNode *e, Type *named_type) { - Type *type = nullptr; - bool ok = check_type_internal(c, e, &type, named_type); - - if (!ok) { - gbString err_str = expr_to_string(e); - error(e, "`%s` is not a type", err_str); - gb_string_free(err_str); - type = t_invalid; - } - - if (type == nullptr) { - type = t_invalid; - } - - if (type->kind == Type_Named && - type->Named.base == nullptr) { - // IMPORTANT TODO(bill): Is this a serious error?! - #if 0 - error(e, "Invalid type definition of `%.*s`", LIT(type->Named.name)); - #endif - type->Named.base = t_invalid; - } - - #if 0 - if (!c->context.allow_polymorphic_types && is_type_polymorphic(type)) { - gbString str = type_to_string(type); - error(e, "Invalid use of a polymorphic type `%s`", str); - gb_string_free(str); - type = t_invalid; - } - #endif - - if (is_type_typed(type)) { - add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value); - } else { - gbString name = type_to_string(type); - error(e, "Invalid type definition of %s", name); - gb_string_free(name); - type = t_invalid; - } - set_base_type(named_type, type); - - return type; -} - bool check_unary_op(Checker *c, Operand *o, Token op) { if (o->type == nullptr) { @@ -3990,35 +1616,6 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { } -String check_down_cast_name(Type *dst_, Type *src_) { - String result = {}; - Type *dst = type_deref(dst_); - Type *src = type_deref(src_); - Type *dst_s = base_type(dst); - GB_ASSERT(dst_s->kind == Type_Struct); - for_array(i, dst_s->Struct.fields) { - Entity *f = dst_s->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); - if (f->flags & EntityFlag_Using) { - if (are_types_identical(f->type, src_)) { - return f->token.string; - } - if (are_types_identical(type_deref(f->type), src_)) { - return f->token.string; - } - - if (!is_type_pointer(f->type)) { - result = check_down_cast_name(f->type, src_); - if (result.len > 0) { - return result; - } - } - } - } - - return result; -} - Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) { GB_ASSERT(node->kind == AstNode_BinaryExpr); ast_node(be, BinaryExpr, node); |