aboutsummaryrefslogtreecommitdiff
path: root/src/check_type.cpp
diff options
context:
space:
mode:
authorCourtney Strachan <courtney.strachan@gmail.com>2025-10-06 02:41:44 +0100
committerGitHub <noreply@github.com>2025-10-06 02:41:44 +0100
commit6de2d6e8ca687c989bbb7806e5cbe8d791e425bf (patch)
tree03a2e0a84c7c1530215f8e3f59a7f643b39b3677 /src/check_type.cpp
parentdbbe96ae5c343f0e803de6ee508207a62571534f (diff)
parent0f97382fa3e46da80705c00dfe02f3deb9562e4f (diff)
Merge branch 'odin-lang:master' into master
Diffstat (limited to 'src/check_type.cpp')
-rw-r--r--src/check_type.cpp132
1 files changed, 94 insertions, 38 deletions
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 9d4defbb2..0819de217 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -267,28 +267,39 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_,
gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type) {
- mutex_lock(&ctx->info->gen_types_mutex); // @@global
-
GenTypesData *found_gen_types = nullptr;
- auto *found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type);
- if (found_gen_types_ptr == nullptr) {
+
+ GB_ASSERT(original_type->kind == Type_Named);
+ mutex_lock(&original_type->Named.gen_types_data_mutex);
+ if (original_type->Named.gen_types_data == nullptr) {
GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData);
gen_types->types = array_make<Entity *>(heap_allocator());
- map_set(&ctx->info->gen_types, original_type, gen_types);
- found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type);
+ original_type->Named.gen_types_data = gen_types;
}
- found_gen_types = *found_gen_types_ptr;
- GB_ASSERT(found_gen_types != nullptr);
- mutex_unlock(&ctx->info->gen_types_mutex); // @@global
+ found_gen_types = original_type->Named.gen_types_data;
+
+ mutex_unlock(&original_type->Named.gen_types_data_mutex);
+
return found_gen_types;
}
gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) {
GB_ASSERT(is_type_named(named_type));
+ GB_ASSERT(original_type->kind == Type_Named);
gbAllocator a = heap_allocator();
Scope *s = ctx->scope->parent;
+ AstPackage *pkg = nullptr;
+ if (original_type->Named.type_name && original_type->Named.type_name->pkg) {
+ pkg = original_type->Named.type_name->pkg;
+ }
+
+ if (pkg == nullptr) {
+ // NOTE(bill): if the `pkg` cannot be determined, default to the current context's pkg instead
+ pkg = ctx->pkg;
+ }
+
Entity *e = nullptr;
{
Token token = ast_token(node);
@@ -300,12 +311,12 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T
e = alloc_entity_type_name(s, token, named_type);
e->state = EntityState_Resolved;
e->file = ctx->file;
- e->pkg = ctx->pkg;
+ e->pkg = pkg;
+ e->TypeName.original_type_for_parapoly = original_type;
add_entity_use(ctx, node, e);
}
named_type->Named.type_name = e;
- GB_ASSERT(original_type->kind == Type_Named);
e->TypeName.objc_class_name = original_type->Named.type_name->TypeName.objc_class_name;
// TODO(bill): Is this even correct? Or should the metadata be copied?
e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata;
@@ -646,7 +657,6 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
struct_type->Struct.node = node;
struct_type->Struct.scope = ctx->scope;
struct_type->Struct.is_packed = st->is_packed;
- struct_type->Struct.is_no_copy = st->is_no_copy;
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
ctx, st->polymorphic_params,
&struct_type->Struct.is_polymorphic,
@@ -1097,7 +1107,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
GB_ASSERT(fields.count <= bf->fields.count);
- auto bit_offsets = slice_make<i64>(permanent_allocator(), fields.count);
+ auto bit_offsets = permanent_slice_make<i64>(fields.count);
i64 curr_offset = 0;
for_array(i, bit_sizes) {
bit_offsets[i] = curr_offset;
@@ -1155,8 +1165,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
}
}
-
-
+ #if 0 // Reconsider at a later date
if (bit_sizes.count > 0 && is_type_integer(backing_type)) {
bool all_booleans = is_type_boolean(fields[0]->type);
bool all_ones = bit_sizes[0] == 1;
@@ -1182,7 +1191,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
}
}
}
-
+ #endif
bit_field_type->BitField.fields = slice_from_array(fields);
bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes);
@@ -1911,9 +1920,18 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
case ParameterValue_Location:
case ParameterValue_Expression:
case ParameterValue_Value:
+ // Special case for polymorphic procedures as default values
+ if (param_value.ast_value != nullptr) {
+ Entity *e = entity_from_expr(param_value.ast_value);
+ if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type)) {
+ // Allow polymorphic procedures as default parameter values
+ // The type will be correctly determined at call site
+ break;
+ }
+ }
gbString str = type_to_string(type);
error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str);
- gb_string_free(str);
+ gb_string_free(str);
break;
}
}
@@ -2068,7 +2086,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
if (op.mode == Addressing_Constant) {
poly_const = op.value;
} else {
- error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr));
+ if (!ctx->in_proc_group) {
+ error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr));
+ }
success = false;
}
}
@@ -2082,7 +2102,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
if (type != t_invalid && !check_is_assignable_to(ctx, &op, type, allow_array_programming)) {
bool ok = true;
if (p->flags&FieldFlag_any_int) {
- if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
+ if (op.type == nullptr) {
+ ok = false;
+ } else if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
ok = false;
} else if (!check_is_castable_to(ctx, &op, type)) {
ok = false;
@@ -2686,7 +2708,7 @@ gb_internal Type *get_map_cell_type(Type *type) {
// Padding exists
Type *s = alloc_type_struct();
Scope *scope = create_scope(nullptr, nullptr);
- s->Struct.fields = slice_make<Entity *>(permanent_allocator(), 2);
+ s->Struct.fields = permanent_slice_make<Entity *>(2);
s->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("v"), alloc_type_array(type, len), false, 0, EntityState_Resolved);
s->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("_"), alloc_type_array(t_u8, padding), false, 1, EntityState_Resolved);
s->Struct.scope = scope;
@@ -2711,7 +2733,7 @@ gb_internal void init_map_internal_debug_types(Type *type) {
Type *metadata_type = alloc_type_struct();
Scope *metadata_scope = create_scope(nullptr, nullptr);
- metadata_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 5);
+ metadata_type->Struct.fields = permanent_slice_make<Entity *>(5);
metadata_type->Struct.fields[0] = alloc_entity_field(metadata_scope, make_token_ident("key"), key, false, 0, EntityState_Resolved);
metadata_type->Struct.fields[1] = alloc_entity_field(metadata_scope, make_token_ident("value"), value, false, 1, EntityState_Resolved);
metadata_type->Struct.fields[2] = alloc_entity_field(metadata_scope, make_token_ident("hash"), t_uintptr, false, 2, EntityState_Resolved);
@@ -2729,7 +2751,7 @@ gb_internal void init_map_internal_debug_types(Type *type) {
Scope *scope = create_scope(nullptr, nullptr);
Type *debug_type = alloc_type_struct();
- debug_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 3);
+ debug_type->Struct.fields = permanent_slice_make<Entity *>(3);
debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), metadata_type, false, 0, EntityState_Resolved);
debug_type->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("len"), t_int, false, 1, EntityState_Resolved);
debug_type->Struct.fields[2] = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, 2, EntityState_Resolved);
@@ -2773,6 +2795,21 @@ gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
return;
}
+ if (key->kind == Type_Basic) {
+ if (key->Basic.flags & BasicFlag_Quaternion) {
+ add_package_dependency(ctx, "runtime", "default_hasher_f64");
+ add_package_dependency(ctx, "runtime", "default_hasher_quaternion256");
+ return;
+ } else if (key->Basic.flags & BasicFlag_Complex) {
+ add_package_dependency(ctx, "runtime", "default_hasher_f64");
+ add_package_dependency(ctx, "runtime", "default_hasher_complex128");
+ return;
+ } else if (key->Basic.flags & BasicFlag_Float) {
+ add_package_dependency(ctx, "runtime", "default_hasher_f64");
+ return;
+ }
+ }
+
if (key->kind == Type_Struct) {
add_package_dependency(ctx, "runtime", "default_hasher");
for_array(i, key->Struct.fields) {
@@ -2947,13 +2984,13 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis
if (wait_to_finish) {
wait_signal_until_available(&old_struct->Struct.fields_wait_signal);
} else {
- GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load());
+ GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load() != 0);
}
field_count = old_struct->Struct.fields.count;
- t->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
- t->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
+ t->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
+ t->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count);
auto const &add_entity = [](Scope *scope, Entity *entity) {
@@ -3071,7 +3108,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
if (is_polymorphic) {
field_count = 0;
- soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
+ soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
soa_struct->Struct.soa_count = 0;
@@ -3081,7 +3118,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
Type *old_array = base_type(elem);
field_count = cast(isize)old_array->Array.count;
- soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
+ soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
string_map_init(&scope->elements, 8);
@@ -3123,8 +3160,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
if (old_struct->Struct.fields_wait_signal.futex.load()) {
field_count = old_struct->Struct.fields.count;
- soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
- soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
+ soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
+ soa_struct->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count);
for_array(i, old_struct->Struct.fields) {
Entity *old_field = old_struct->Struct.fields[i];
@@ -3259,7 +3296,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
}
if (count < 0) {
- error(at->count, "? can only be used in conjuction with compound literals");
+ error(at->count, "? can only be used in conjunction with compound literals");
count = 0;
}
@@ -3281,8 +3318,11 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
if (generic_type != nullptr) {
// Ignore
} else if (count < 1 || !is_power_of_two(count)) {
- error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count);
*type = alloc_type_array(elem, count, generic_type);
+ if (ctx->disallow_polymorphic_return_types && count == 0) {
+ return;
+ }
+ error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count);
return;
}
@@ -3316,7 +3356,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
}
}
gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
- GB_ASSERT_NOT_NULL(type);
+ GB_ASSERT(type != nullptr);
if (e == nullptr) {
*type = t_invalid;
return true;
@@ -3473,8 +3513,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
case_ast_node(pt, PointerType, e);
CheckerContext c = *ctx;
- c.type_path = new_checker_type_path();
- defer (destroy_checker_type_path(c.type_path));
+
+ TEMPORARY_ALLOCATOR_GUARD();
+ c.type_path = new_checker_type_path(temporary_allocator());
Type *elem = t_invalid;
Operand o = {};
@@ -3502,6 +3543,17 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
elem = o.type;
}
+ if (!ctx->in_polymorphic_specialization && ctx->disallow_polymorphic_return_types) {
+ Type *t = base_type(elem);
+ if (t != nullptr &&
+ unparen_expr(pt->type)->kind == Ast_Ident &&
+ is_type_polymorphic_record_unspecialized(t)) {
+ gbString err_str = expr_to_string(e);
+ error(e, "Invalid use of a non-specialized polymorphic type '%s'", err_str);
+ gb_string_free(err_str);
+ }
+ }
+
if (pt->tag != nullptr) {
GB_ASSERT(pt->tag->kind == Ast_BasicDirective);
@@ -3697,8 +3749,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
CheckerContext c = *ctx;
- c.type_path = new_checker_type_path();
- defer (destroy_checker_type_path(c.type_path));
+ TEMPORARY_ALLOCATOR_GUARD();
+ c.type_path = new_checker_type_path(temporary_allocator());
return check_type_expr(&c, e, nullptr);
}
@@ -3766,7 +3818,11 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type)
#if 0
error(e, "Invalid type definition of '%.*s'", LIT(type->Named.name));
#endif
- type->Named.base = t_invalid;
+ if (type->Named.type_name->TypeName.is_type_alias) {
+ // NOTE(laytan): keep it null, type declaration is a mini "cycle" to be filled later.
+ } else {
+ type->Named.base = t_invalid;
+ }
}
if (is_type_polymorphic(type)) {
@@ -3784,7 +3840,7 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type)
}
#endif
- if (is_type_typed(type)) {
+ if (type->kind == Type_Named && type->Named.base == nullptr || is_type_typed(type)) {
add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value);
} else {
gbString name = type_to_string(type);