aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-12-01 11:53:08 +0000
committergingerBill <gingerBill@users.noreply.github.com>2025-12-01 11:53:08 +0000
commit3771ff7b123bf1debe2da2886d833791ee890b39 (patch)
tree69cc14a85ef5cb47ede1280df76f6206aa934d00 /src
parent9f80d697027a41a9c36b8eb42d9c98f9b7fcbe2c (diff)
parente72aad983bb683858a1aee935b2956ced40f69f8 (diff)
Merge branch 'master' into vendor/curl
Diffstat (limited to 'src')
-rw-r--r--src/check_builtin.cpp124
-rw-r--r--src/check_decl.cpp3
-rw-r--r--src/check_expr.cpp115
-rw-r--r--src/check_type.cpp9
-rw-r--r--src/checker.cpp32
-rw-r--r--src/checker_builtin_procs.hpp2
-rw-r--r--src/docs_format.cpp62
-rw-r--r--src/docs_writer.cpp7
-rw-r--r--src/llvm_backend.cpp14
-rw-r--r--src/llvm_backend_const.cpp40
-rw-r--r--src/llvm_backend_debug.cpp6
-rw-r--r--src/llvm_backend_expr.cpp9
-rw-r--r--src/llvm_backend_proc.cpp2
-rw-r--r--src/llvm_backend_stmt.cpp13
-rw-r--r--src/llvm_backend_type.cpp33
-rw-r--r--src/llvm_backend_utility.cpp2
-rw-r--r--src/main.cpp34
-rw-r--r--src/name_canonicalization.cpp177
-rw-r--r--src/parser.cpp25
-rw-r--r--src/parser.hpp1
-rw-r--r--src/tilde_type_info.cpp12
-rw-r--r--src/types.cpp13
-rw-r--r--src/ucg/ucg.c2
-rw-r--r--src/ucg/ucg_tables.h2
24 files changed, 626 insertions, 113 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index b2d28afc0..1b3e6912c 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -2485,6 +2485,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_min:
case BuiltinProc_max:
case BuiltinProc_type_is_subtype_of:
+ case BuiltinProc_type_is_superset_of:
case BuiltinProc_objc_send:
case BuiltinProc_objc_find_selector:
case BuiltinProc_objc_find_class:
@@ -7397,6 +7398,129 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
operand->type = t_untyped_bool;
} break;
+ case BuiltinProc_type_is_superset_of:
+ {
+ Operand op_super = {};
+ Operand op_sub = {};
+
+ check_expr_or_type(c, &op_super, ce->args[0]);
+ if (op_super.mode != Addressing_Type) {
+ gbString e = expr_to_string(op_super.expr);
+ error(op_super.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e);
+ gb_string_free(e);
+ return false;
+ }
+ check_expr_or_type(c, &op_sub, ce->args[1]);
+ if (op_sub.mode != Addressing_Type) {
+ gbString e = expr_to_string(op_sub.expr);
+ error(op_sub.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e);
+ gb_string_free(e);
+ return false;
+ }
+
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_bool;
+
+ Type *super = op_super.type;
+ Type *sub = op_sub.type;
+ if (are_types_identical(super, sub)) {
+ operand->value = exact_value_bool(true);
+ return true;
+ }
+
+ super = base_type(super);
+ sub = base_type(sub);
+ if (are_types_identical(super, sub)) {
+ operand->value = exact_value_bool(true);
+ return true;
+ }
+
+ if (super->kind != sub->kind) {
+ gbString a = type_to_string(op_super.type);
+ gbString b = type_to_string(op_sub.type);
+ error(op_super.expr, "'%.*s' expects types of the same kind, got %s vs %s", LIT(builtin_name), a, b);
+ gb_string_free(b);
+ gb_string_free(a);
+ return false;
+ }
+
+ if (super->kind == Type_Enum) {
+ if (sub->Enum.fields.count > super->Enum.fields.count) {
+ operand->value = exact_value_bool(false);
+ return true;
+ }
+
+
+ Type *base_super = base_enum_type(super);
+ Type *base_sub = base_enum_type(sub);
+ if (base_super == base_sub && base_super == nullptr) {
+ // okay
+ } else if (!are_types_identical(base_type(base_super), base_type(base_sub))) {
+ operand->value = exact_value_bool(false);
+ return true;
+ }
+
+ for (Entity *f_sub : sub->Enum.fields) {
+ bool found = false;
+
+ if (f_sub->kind != Entity_Constant) {
+ continue;
+ }
+
+ for (Entity *f_super : super->Enum.fields) {
+ if (f_super->kind != Entity_Constant) {
+ continue;
+ }
+
+ if (f_sub->token.string == f_super->token.string) {
+ if (compare_exact_values(Token_CmpEq, f_sub->Constant.value, f_super->Constant.value)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ operand->value = exact_value_bool(false);
+ return true;
+ }
+ }
+
+ operand->value = exact_value_bool(true);
+ return true;
+
+ } else if (super->kind == Type_Union) {
+ if (sub->Union.variants.count > super->Union.variants.count) {
+ operand->value = exact_value_bool(false);
+ return true;
+ }
+ if (sub->Union.kind != super->Union.kind) {
+ operand->value = exact_value_bool(false);
+ return true;
+ }
+
+ for_array(i, sub->Union.variants) {
+ Type *t_sub = sub->Union.variants[i];
+ Type *t_super = super->Union.variants[i];
+ if (!are_types_identical(t_sub, t_super)) {
+ operand->value = exact_value_bool(false);
+ return true;
+ }
+ }
+
+ operand->value = exact_value_bool(true);
+ return true;
+
+ }
+ gbString a = type_to_string(op_super.type);
+ gbString b = type_to_string(op_sub.type);
+ error(op_super.expr, "'%.*s' expects types of the same kind and either an enum or union, got %s vs %s", LIT(builtin_name), a, b);
+ gb_string_free(b);
+ gb_string_free(a);
+ return false;
+ }
+
+
case BuiltinProc_type_field_index_of:
{
Operand op = {};
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index e54943d80..27babd255 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -1607,8 +1607,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
if (is_arch_wasm() && foreign_library != nullptr) {
// NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later
mpsc_enqueue(&ctx->info->foreign_decls_to_check, e);
- } else {
- // TODO(harold): Check if it's an objective-C foreign, if so, I don't think we need to check it.
+ } else if (!e->Procedure.is_objc_impl_or_import) {
check_foreign_procedure(ctx, e, d);
}
} else {
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index e22f12323..418fb5378 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -9200,6 +9200,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
return kind;
}
+
+gb_internal void check_expr_as_value_for_ternary(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) {
+ check_expr_base(c, o, e, type_hint);
+ check_not_tuple(c, o);
+ error_operand_no_value(o);
+
+ switch (o->mode) {
+ case Addressing_Type: {
+ ERROR_BLOCK();
+ gbString expr_str = expr_to_string(o->expr);
+ defer (gb_string_free(expr_str));
+
+ error(o->expr, "A type '%s' cannot be used as a runtime value", expr_str);
+
+ error_line("\tSuggestion: If a runtime 'typeid' is wanted, use 'typeid_of' to convert a type\n");
+
+ o->mode = Addressing_Invalid;
+
+ } break;
+
+ case Addressing_Builtin: {
+ ERROR_BLOCK();
+ gbString expr_str = expr_to_string(o->expr);
+ defer (gb_string_free(expr_str));
+
+ error(o->expr, "A built-in procedure '%s' cannot be used as a runtime value", expr_str);
+
+ error_line("\tNote: Built-in procedures are implemented by the compiler and might not be actually instantiated procedures\n");
+
+ o->mode = Addressing_Invalid;
+ } break;
+
+ case Addressing_ProcGroup: {
+ ERROR_BLOCK();
+ gbString expr_str = expr_to_string(o->expr);
+ defer (gb_string_free(expr_str));
+
+ error(o->expr, "Cannot use overloaded procedure '%s' as a runtime value", expr_str);
+
+ error_line("\tNote: Please specify which procedure in the procedure group to use, via cast or type inference\n");
+
+ o->mode = Addressing_Invalid;
+ } break;
+ }
+}
+
gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
ExprKind kind = Expr_Expr;
Operand cond = {Addressing_Invalid};
@@ -9213,7 +9259,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
Operand x = {Addressing_Invalid};
Operand y = {Addressing_Invalid};
- check_expr_or_type(c, &x, te->x, type_hint);
+ check_expr_as_value_for_ternary(c, &x, te->x, type_hint);
node->viral_state_flags |= te->x->viral_state_flags;
if (te->y != nullptr) {
@@ -9221,7 +9267,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
if (type_hint == nullptr && is_type_typed(x.type)) {
th = x.type;
}
- check_expr_or_type(c, &y, te->y, th);
+ check_expr_as_value_for_ternary(c, &y, te->y, th);
node->viral_state_flags |= te->y->viral_state_flags;
} else {
error(node, "A ternary expression must have an else clause");
@@ -9248,6 +9294,20 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
return kind;
}
+ if (x.mode == Addressing_Builtin && y.mode == Addressing_Builtin) {
+ if (type_hint == nullptr) {
+ error(node, "Built-in procedures cannot be used within a ternary expression since they have no well-defined signature");
+ return kind;
+ }
+ }
+
+ if (x.mode == Addressing_ProcGroup && y.mode == Addressing_ProcGroup) {
+ if (type_hint == nullptr) {
+ error(node, "Procedure groups cannot be used within a ternary expression since they have no well-defined signature that can be inferred without a context");
+ return kind;
+ }
+ }
+
// NOTE(bill, 2023-01-30): Allow for expression like this:
// x: union{f32} = f32(123) if cond else nil
if (type_hint && !is_type_any(type_hint)) {
@@ -9778,6 +9838,57 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
c->bit_field_bit_size = prev_bit_field_bit_size;
}
+
+ if (bt->kind == Type_Struct && bt->Struct.is_all_or_none && elems.count > 0 && bt->Struct.fields.count > 0) {
+ PtrSet<Entity *> missing_fields = {};
+ defer (ptr_set_destroy(&missing_fields));
+
+ for_array(i, bt->Struct.fields) {
+ Entity *field = bt->Struct.fields[i];
+ String name = field->token.string;
+ if (is_blank_ident(name) || name == "") {
+ continue;
+ }
+ bool found = string_set_exists(&fields_visited, name);
+ String *raw_union = string_map_get(&fields_visited_through_raw_union, name);
+ if (!found && raw_union == nullptr) {
+ ptr_set_add(&missing_fields, field);
+ }
+ }
+
+ if (missing_fields.count > 0) {
+ Ast *expr = o->expr;
+ if (expr == nullptr) {
+ GB_ASSERT(elems.count > 0);
+ expr = elems[elems.count-1];
+ }
+
+ ERROR_BLOCK();
+
+ if (build_context.terse_errors) {
+ gbString fields_string = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(fields_string));
+ isize i = 0;
+ FOR_PTR_SET(field, missing_fields) {
+ if (i > 0) {
+ fields_string = gb_string_appendc(fields_string, ", ");
+ }
+ String name = field->token.string;
+ fields_string = gb_string_append_length(fields_string, name.text, name.len);
+ i += 1;
+ }
+
+ error(expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields: %s", fields_string);
+ } else {
+ error(expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields:");
+ FOR_PTR_SET(field, missing_fields) {
+ gbString s = type_to_string(field->type);
+ error_line("\t%.*s: %s\n", LIT(field->token.string), s);
+ gb_string_free(s);
+ }
+ }
+ }
+ }
}
gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
diff --git a/src/check_type.cpp b/src/check_type.cpp
index f1a2e9e22..af07efd8f 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -654,9 +654,10 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
context = str_lit("struct #raw_union");
}
- struct_type->Struct.node = node;
- struct_type->Struct.scope = ctx->scope;
- struct_type->Struct.is_packed = st->is_packed;
+ struct_type->Struct.node = node;
+ struct_type->Struct.scope = ctx->scope;
+ struct_type->Struct.is_packed = st->is_packed;
+ struct_type->Struct.is_all_or_none = st->is_all_or_none;
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
ctx, st->polymorphic_params,
&struct_type->Struct.is_polymorphic,
@@ -1633,6 +1634,8 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
} else if (expr->kind == Ast_Ident) {
Operand x= {};
Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, true);
+ GB_ASSERT(e != nullptr);
+
if (e->flags & EntityFlag_Param) {
return true;
}
diff --git a/src/checker.cpp b/src/checker.cpp
index 8b3638c9d..4d5482933 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -790,8 +790,10 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl
// Is >256 KiB good enough?
if (sz > 1ll<<18) {
bool is_ref = false;
- if((e->flags & EntityFlag_ForValue) != 0) {
+ if ((e->flags & EntityFlag_ForValue) != 0) {
is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL;
+ } else if ((e->flags & EntityFlag_SwitchValue) != 0) {
+ is_ref = !(e->flags & EntityFlag_Value);
}
if(!is_ref) {
gbString type_str = type_to_string(e->type);
@@ -923,6 +925,22 @@ gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) {
return *found;
}
+
+gb_internal AstPackage *try_get_core_package(CheckerInfo *info, String name) {
+ if (name == "runtime") {
+ return get_runtime_package(info);
+ }
+
+ gbAllocator a = heap_allocator();
+ String path = get_fullpath_core_collection(a, name, nullptr);
+ defer (gb_free(a, path.text));
+ auto found = string_map_get(&info->packages, path);
+ if (found == nullptr) {
+ return nullptr;
+ }
+ return *found;
+}
+
gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) {
String n = make_string_c(name);
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
@@ -7015,9 +7033,11 @@ gb_internal void check_objc_context_provider_procedures(Checker *c) {
}
}
-gb_internal void check_unique_package_names(Checker *c) {
+gb_internal bool check_unique_package_names(Checker *c) {
ERROR_BLOCK();
+ bool ok = true;
+
StringMap<AstPackage *> pkgs = {}; // Key: package name
string_map_init(&pkgs, 2*c->info.packages.count);
defer (string_map_destroy(&pkgs));
@@ -7042,6 +7062,7 @@ gb_internal void check_unique_package_names(Checker *c) {
continue;
}
+ ok = false;
begin_error_block();
error(curr, "Duplicate declaration of 'package %.*s'", LIT(name));
@@ -7064,6 +7085,8 @@ gb_internal void check_unique_package_names(Checker *c) {
end_error_block();
}
+
+ return ok;
}
gb_internal void check_add_entities_from_queues(Checker *c) {
@@ -7446,7 +7469,7 @@ gb_internal void check_parsed_files(Checker *c) {
debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed));
TIME_SECTION("check unique package names");
- check_unique_package_names(c);
+ bool package_names_are_unique = check_unique_package_names(c);
TIME_SECTION("sanity checks");
check_merge_queues_into_arrays(c);
@@ -7503,7 +7526,8 @@ gb_internal void check_parsed_files(Checker *c) {
c->info.type_info_types_hash_map[index] = tt;
bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index);
- if (exists) {
+ // Because we've already written a nice error about a duplicate package declaration, skip this panic if the package names aren't unique.
+ if (package_names_are_unique && exists) {
for (auto const &entry : c->info.min_dep_type_info_index_map) {
if (entry.key != tt.hash) {
continue;
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index 663274cdc..5b446cc1c 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -336,6 +336,7 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_polymorphic_record_parameter_value,
BuiltinProc_type_is_subtype_of,
+ BuiltinProc_type_is_superset_of,
BuiltinProc_type_field_index_of,
@@ -708,6 +709,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_subtype_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_is_superset_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics },
{STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
diff --git a/src/docs_format.cpp b/src/docs_format.cpp
index 6378971d0..2235789d5 100644
--- a/src/docs_format.cpp
+++ b/src/docs_format.cpp
@@ -94,6 +94,7 @@ enum OdinDocTypeFlag_Struct : u32 {
OdinDocTypeFlag_Struct_polymorphic = 1<<0,
OdinDocTypeFlag_Struct_packed = 1<<1,
OdinDocTypeFlag_Struct_raw_union = 1<<2,
+ OdinDocTypeFlag_Struct_all_or_none = 1<<3,
};
enum OdinDocTypeFlag_Union : u32 {
@@ -124,21 +125,76 @@ enum {
struct OdinDocType {
OdinDocTypeKind kind;
+ // Type_Kind specific used by some types
+ // Underlying flag types:
+ // .Basic - Type_Flags_Basic
+ // .Struct - Type_Flags_Struct
+ // .Union - Type_Flags_Union
+ // .Proc - Type_Flags_Proc
+ // .Bit_Set - Type_Flags_Bit_Set
u32 flags;
+
+ // Used by:
+ // .Basic
+ // .Named
+ // .Generic
OdinDocString name;
+
+ // Used By: .Struct, .Union
OdinDocString custom_align;
- // Used by some types
+ // Used by:
+ // .Array - 1 count: 0=len
+ // .Enumerated_Array - 1 count: 0=len
+ // .SOA_Struct_Fixed - 1 count: 0=len
+ // .Bit_Set - 2 count: 0=lower, 1=upper
+ // .Simd_Vector - 1 count: 0=len
+ // .Matrix - 2 count: 0=row_count, 1=column_count
+ // .Struct - <=2 count: 0=min_field_align, 1=max_field_align
u32 elem_count_len;
i64 elem_counts[OdinDocType_ElemsCap];
- // Each of these is esed by some types, not all
+ // Used by: .Procedures
+ // blank implies the "odin" calling convention
OdinDocString calling_convention;
+
+ // Used by:
+ // .Named - 1 type: 0=base type
+ // .Generic - <1 type: 0=specialization
+ // .Pointer - 1 type: 0=element
+ // .Array - 1 type: 0=element
+ // .Enumerated_Array - 2 types: 0=index and 1=element
+ // .Slice - 1 type: 0=element
+ // .Dynamic_Array - 1 type: 0=element
+ // .Map - 2 types: 0=key, 1=value
+ // .SOA_Struct_Fixed - 1 type: underlying SOA struct element
+ // .SOA_Struct_Slice - 1 type: underlying SOA struct element
+ // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element
+ // .Union - 0+ types: variants
+ // .Enum - <1 type: 0=base type
+ // .Proc - 2 types: 0=parameters, 1=results
+ // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set)
+ // .Simd_Vector - 1 type: 0=element
+ // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer
+ // .Multi_Pointer - 1 type: 0=element
+ // .Matrix - 1 type: 0=element
+ // .Soa_Pointer - 1 type: 0=element
+ // .Bit_Field - 1 type: 0=backing type
OdinDocArray<OdinDocTypeIndex> types;
+
+ // Used by:
+ // .Named - 1 field for the definition
+ // .Struct - fields
+ // .Enum - fields
+ // .Parameters - parameters (procedures only)
OdinDocArray<OdinDocEntityIndex> entities;
+
+ // Used By: .Struct, .Union
OdinDocTypeIndex polmorphic_params;
+ // Used By: .Struct, .Union
OdinDocArray<OdinDocString> where_clauses;
- OdinDocArray<OdinDocString> tags; // struct field tags
+ // Used By: .Struct
+ OdinDocArray<OdinDocString> tags;
};
struct OdinDocAttribute {
diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp
index 1f2325980..3edd7da9d 100644
--- a/src/docs_writer.cpp
+++ b/src/docs_writer.cpp
@@ -620,6 +620,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool ca
if (type->Struct.is_polymorphic) { doc_type.flags |= OdinDocTypeFlag_Struct_polymorphic; }
if (type->Struct.is_packed) { doc_type.flags |= OdinDocTypeFlag_Struct_packed; }
if (type->Struct.is_raw_union) { doc_type.flags |= OdinDocTypeFlag_Struct_raw_union; }
+ if (type->Struct.is_all_or_none) { doc_type.flags |= OdinDocTypeFlag_Struct_all_or_none; }
+
+ if (type->Struct.custom_min_field_align > 0 || type->Struct.custom_max_field_align > 0) {
+ doc_type.elem_count_len = 2;
+ doc_type.elem_counts[0] = cast(u32)gb_max(type->Struct.custom_min_field_align, 0);
+ doc_type.elem_counts[1] = cast(u32)gb_max(type->Struct.custom_max_field_align, 0);
+ }
auto fields = array_make<OdinDocEntityIndex>(heap_allocator(), type->Struct.fields.count);
defer (array_free(&fields));
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 22a481187..71bca42ab 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -2090,6 +2090,7 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur
name = gb_string_append_length(name, ename.text, ename.len);
lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type);
+ dummy->is_startup = true;
LLVMSetVisibility(dummy->value, LLVMHiddenVisibility);
LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage);
@@ -2900,7 +2901,18 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
args[0] = lb_addr_load(p, all_tests_slice);
lbValue result = lb_emit_call(p, runner, args);
- lbValue exit_runner = lb_find_package_value(m, str_lit("os"), str_lit("exit"));
+ lbValue exit_runner = {};
+ {
+ AstPackage *pkg = get_runtime_package(m->info);
+
+ String name = str_lit("exit");
+ Entity *e = scope_lookup_current(pkg->scope, name);
+ if (e == nullptr) {
+ compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg->name), LIT(name));
+ }
+ exit_runner = lb_find_value_from_entity(m, e);
+ }
+
auto exit_args = array_make<lbValue>(temporary_allocator(), 1);
exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1));
lb_emit_call(p, exit_runner, exit_args, ProcInlining_none);
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index a7117fe0b..22e124792 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -185,8 +185,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
}
Type *bt = base_type(t);
GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union);
-
- GB_ASSERT(value_count_ == bt->Struct.fields.count);
+ GB_ASSERT(bt->kind != Type_Struct || value_count_ == bt->Struct.fields.count);
auto field_remapping = lb_get_struct_remapping(m, t);
unsigned values_with_padding_count = elem_count;
@@ -513,7 +512,7 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi
max_count = mp_pack_count(a, nails, size);
if (sz < max_count) {
debug_print_big_int(a);
- gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz);;
+ gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz);
}
GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu, type %s", max_count, sz, written, type_to_string(original_type));
GB_ASSERT(gb_size_of(rop64) >= sz);
@@ -691,11 +690,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
} else if (bt->Union.variants.count == 1) {
if (value.kind == ExactValue_Compound) {
ast_node(cl, CompoundLit, value.value_compound);
- if (cl->elems.count == 0 && cl->type == nullptr) {
- return lb_const_nil(m, original_type);
+ if (cl->elems.count == 0) {
+ if (cl->type == nullptr) {
+ return lb_const_nil(m, original_type);
+ }
+ if (are_types_identical(type_of_expr(cl->type), original_type)) {
+ return lb_const_nil(m, original_type);
+ }
}
}
+ if (value_type == t_untyped_nil) {
+ return lb_const_nil(m, original_type);
+ }
+
Type *t = bt->Union.variants[0];
lbValue cv = lb_const_value(m, t, value, cc);
GB_ASSERT(LLVMIsConstant(cv.value));
@@ -736,6 +744,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
} else if (value.kind == ExactValue_Invalid) {
return lb_const_nil(m, original_type);
}
+ } else if (value_type == t_untyped_nil) {
+ return lb_const_nil(m, original_type);
}
GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value));
@@ -792,13 +802,21 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
if (value.kind == ExactValue_Procedure) {
lbValue res = {};
- Ast *expr = unparen_expr(value.value_procedure);
- GB_ASSERT(expr != nullptr);
- if (expr->kind == Ast_ProcLit) {
- res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
- } else {
+ for (;;) {
+ Ast *expr = unparen_expr(value.value_procedure);
+ GB_ASSERT(expr != nullptr);
+ if (expr->kind == Ast_ProcLit) {
+ res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
+ break;
+ }
Entity *e = entity_from_expr(expr);
- res = lb_find_procedure_value_from_entity(m, e);
+ GB_ASSERT(e != nullptr);
+ if (e->kind != Entity_Constant) {
+ res = lb_find_procedure_value_from_entity(m, e);
+ break;
+ }
+ value = e->Constant.value;
+ GB_ASSERT(value.kind == ExactValue_Procedure);
}
if (res.value == nullptr) {
// This is an unspecialized polymorphic procedure, return nil or dummy value
diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp
index 3372165f2..187aebf7c 100644
--- a/src/llvm_backend_debug.cpp
+++ b/src/llvm_backend_debug.cpp
@@ -704,7 +704,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned);
case Basic_typeid:
- return lb_debug_type_basic_type(m, str_lit("typeid"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned);
+ return lb_debug_type_basic_type(m, str_lit("typeid"), 64, LLVMDWARFTypeEncoding_Unsigned);
// Endian Specific Types
case Basic_i16le: return lb_debug_type_basic_type(m, str_lit("i16le"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian);
@@ -820,8 +820,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
{
LLVMMetadataRef elements[2] = {};
elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0);
- elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, ptr_bits);
- return lb_debug_basic_struct(m, str_lit("any"), 2*ptr_bits, ptr_bits, elements, gb_count_of(elements));
+ elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, 64);
+ return lb_debug_basic_struct(m, str_lit("any"), 128, 64, elements, gb_count_of(elements));
}
// Untyped types
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index 187c34595..d5658b9d5 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -634,7 +634,7 @@ gb_internal LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m)
}
-gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
+gb_internal lbValue lb_emit_matrix_transpose(lbProcedure *p, lbValue m, Type *type) {
if (is_type_array(m.type)) {
i32 rank = type_math_rank(m.type);
if (rank == 2) {
@@ -664,7 +664,12 @@ gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *typ
Type *mt = base_type(m.type);
GB_ASSERT(mt->kind == Type_Matrix);
- if (lb_is_matrix_simdable(mt)) {
+ Type *rt = base_type(type);
+ if (rt->kind == Type_Matrix && rt->Matrix.is_row_major != mt->Matrix.is_row_major) {
+ GB_PANIC("TODO: transpose with changing layout");
+ }
+
+ if (lb_is_matrix_simdable(mt) && lb_is_matrix_simdable(type)) {
unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt);
unsigned row_count = cast(unsigned)mt->Matrix.row_count;
unsigned column_count = cast(unsigned)mt->Matrix.column_count;
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 890556a61..10e10564e 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -2681,7 +2681,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case BuiltinProc_transpose:
{
lbValue m = lb_build_expr(p, ce->args[0]);
- return lb_emit_matrix_tranpose(p, m, tv.type);
+ return lb_emit_matrix_transpose(p, m, tv.type);
}
case BuiltinProc_outer_product:
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index f247fa2a7..3dbcea4fb 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -2178,11 +2178,14 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
LLVMSetLinkage(var_global_ref, LLVMInternalLinkage);
}
- LLVMValueRef vals[2] = {
- lb_emit_conv(p, var_global.addr, t_rawptr).value,
- lb_typeid(p->module, var_type).value,
- };
- LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals, gb_count_of(vals));
+ auto vals = array_make<LLVMValueRef>(temporary_allocator(), 0, 3);
+ array_add(&vals, lb_emit_conv(p, var_global.addr, t_rawptr).value);
+ if (build_context.metrics.ptr_size == 4) {
+ array_add(&vals, LLVMConstNull(lb_type_padding_filler(p->module, 4, 4)));
+ }
+ array_add(&vals, lb_typeid(p->module, var_type).value);
+
+ LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals.data, vals.count);
LLVMSetInitializer(global, init);
} else {
LLVMSetInitializer(global, value.value);
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 7d412eb15..382304a4e 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -181,15 +181,9 @@ gb_internal LLVMTypeRef *lb_setup_modified_types_for_type_info(lbModule *m, isiz
stypes[0] = lb_type(m, tibt->Struct.fields[0]->type);
stypes[1] = lb_type(m, tibt->Struct.fields[1]->type);
stypes[2] = lb_type(m, tibt->Struct.fields[2]->type);
- isize variant_index = 0;
- if (build_context.ptr_size == 8) {
- stypes[3] = lb_type(m, t_i32); // padding
- stypes[4] = lb_type(m, tibt->Struct.fields[3]->type);
- variant_index = 5;
- } else {
- stypes[3] = lb_type(m, tibt->Struct.fields[3]->type);
- variant_index = 4;
- }
+ stypes[3] = lb_type(m, t_i32); // padding
+ stypes[4] = lb_type(m, tibt->Struct.fields[3]->type);
+ isize variant_index = 5;
LLVMTypeRef *modified_types = gb_alloc_array(heap_allocator(), LLVMTypeRef, Typeid__COUNT);
GB_ASSERT(Typeid__COUNT == ut->Union.variants.count);
@@ -360,16 +354,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
small_const_values[0] = LLVMConstInt(lb_type(m, t_int), size, true);
small_const_values[1] = LLVMConstInt(lb_type(m, t_int), align, true);
small_const_values[2] = type_info_flags.value;
-
- unsigned variant_index = 0;
- if (build_context.ptr_size == 8) {
- small_const_values[3] = LLVMConstNull(LLVMStructGetTypeAtIndex(stype, 3));
- small_const_values[4] = id.value;
- variant_index = 5;
- } else {
- small_const_values[3] = id.value;
- variant_index = 4;
- }
+ small_const_values[3] = LLVMConstNull(LLVMStructGetTypeAtIndex(stype, 3));
+ small_const_values[4] = id.value;
+ unsigned variant_index = 5;
LLVMTypeRef full_variant_type = LLVMStructGetTypeAtIndex(stype, variant_index);
unsigned full_variant_elem_count = LLVMCountStructElementTypes(full_variant_type);
@@ -830,10 +817,10 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
{
u8 flags = 0;
- if (t->Struct.is_packed) flags |= 1<<0;
- if (t->Struct.is_raw_union) flags |= 1<<1;
- //
- if (t->Struct.custom_align) flags |= 1<<3;
+ if (t->Struct.is_packed) flags |= 1<<0;
+ if (t->Struct.is_raw_union) flags |= 1<<1;
+ if (t->Struct.is_all_or_none) flags |= 1<<2;
+ if (t->Struct.custom_align) flags |= 1<<3;
vals[6] = lb_const_int(m, t_u8, flags).value;
if (is_type_comparable(t) && !is_type_simple_compare(t)) {
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index c7b4170e9..33ad2ee8d 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -1005,6 +1005,7 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
switch (index) {
case 0: return 0; // data
case 1: return 2; // id
+ default: GB_PANIC("index > 1");
}
} else if (build_context.ptr_size != build_context.int_size) {
switch (t->kind) {
@@ -1203,6 +1204,7 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
switch (index) {
case 0: result_type = t_rawptr; break;
case 1: result_type = t_typeid; break;
+ default: GB_PANIC("index > 1");
}
} else if (is_type_dynamic_array(t)) {
switch (index) {
diff --git a/src/main.cpp b/src/main.cpp
index 83e7d688c..544cd54bb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1309,23 +1309,17 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.vet_flags |= VetFlag_All;
break;
- case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break;
- case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break;
- case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
- case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
- case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
- case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
- case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
- case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
- case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break;
- case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break;
- case BuildFlag_VetUnusedProcedures:
- build_context.vet_flags |= VetFlag_UnusedProcedures;
- if (!set_flags[BuildFlag_VetPackages]) {
- gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name));
- bad_flags = true;
- }
- break;
+ case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break;
+ case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break;
+ case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
+ case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
+ case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
+ case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
+ case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
+ case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
+ case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break;
+ case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break;
+ case BuildFlag_VetUnusedProcedures: build_context.vet_flags |= VetFlag_UnusedProcedures; break;
case BuildFlag_VetPackages:
{
@@ -1788,6 +1782,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
}
+ if (set_flags[BuildFlag_VetUnusedProcedures] && !set_flags[BuildFlag_VetPackages]) {
+ gb_printf_err("-vet-unused-procedures must be used with -vet-packages\n");
+ bad_flags = true;
+ }
+
if ((!(build_context.export_timings_format == TimingsExportUnspecified)) && (build_context.export_timings_file.len == 0)) {
gb_printf_err("`-export-timings:<format>` requires `-export-timings-file:<filename>` to be specified as well\n");
bad_flags = true;
@@ -2681,7 +2680,6 @@ gb_internal int print_show_help(String const arg0, String command, String option
print_usage_line(3, "-integer-division-by-zero:trap Trap on division/modulo/remainder by zero");
print_usage_line(3, "-integer-division-by-zero:zero x/0 == 0 and x%%0 == x and x%%%%0 == x");
print_usage_line(3, "-integer-division-by-zero:self x/0 == x and x%%0 == 0 and x%%%%0 == 0");
- print_usage_line(3, "-integer-division-by-zero:all-bits x/0 == ~T(0) and x%%0 == x and x%%%%0 == x");
}
}
diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp
index 8bacfabc6..f1dccb182 100644
--- a/src/name_canonicalization.cpp
+++ b/src/name_canonicalization.cpp
@@ -242,9 +242,146 @@ gb_internal gb_inline void type_set_clear(TypeSet *s) {
typedef TYPE_WRITER_PROC(TypeWriterProc);
+enum { SIP_BLOCK_SIZE = 8 };
+
+struct SipHashContext {
+ u64 v0, v1, v2, v3; // State values
+ u64 k0, k1; // Split key
+ isize c_rounds; // Number of message rounds
+ isize d_rounds; // Number of finalization rounds
+ u8 buf[SIP_BLOCK_SIZE]; // Provided data
+ isize last_block; // offset from last block
+ isize total_length;
+ bool is_initialized;
+};
+
+struct TypeidHashContext {
+ SipHashContext sip;
+};
+
+
+void typeid_hash_context_init(TypeidHashContext *hash_ctx) {
+ SipHashContext *sip = &hash_ctx->sip;
+ sip->c_rounds = 2;
+ sip->d_rounds = 4;
+
+ // some random numbers to act as the seed
+ sip->k0 = 0xa6592ea25e04ac3cull;
+ sip->k1 = 0xba3cba04ed28a9aeull;
+
+ //
+ sip->v0 = 0x736f6d6570736575 ^ sip->k0;
+ sip->v1 = 0x646f72616e646f6d ^ sip->k1;
+ sip->v2 = 0x6c7967656e657261 ^ sip->k0;
+ sip->v3 = 0x7465646279746573 ^ sip->k1;
+
+ sip->last_block = 0;
+ sip->total_length = 0;
+
+ sip->is_initialized = true;
+}
+
+u64 rotate_left64(u64 x, u64 k) {
+ static u64 const n = 64;
+ u64 s = k & (n-1);
+ return (x<<s) | (x>>(n-2));
+}
+
+void sip_compress(SipHashContext *sip) {
+ sip->v0 += sip->v1;
+ sip->v1 = rotate_left64(sip->v1, 13);
+ sip->v1 ^= sip->v0;
+ sip->v0 = rotate_left64(sip->v0, 32);
+ sip->v2 += sip->v3;
+ sip->v3 = rotate_left64(sip->v3, 16);
+ sip->v3 ^= sip->v2;
+ sip->v0 += sip->v3;
+ sip->v3 = rotate_left64(sip->v3, 21);
+ sip->v3 ^= sip->v0;
+ sip->v2 += sip->v1;
+ sip->v1 = rotate_left64(sip->v1, 17);
+ sip->v1 ^= sip->v2;
+ sip->v2 = rotate_left64(sip->v2, 32);
+}
+
+void sip_block(SipHashContext *sip, void const *ptr, isize len) {
+ u8 const *data = cast(u8 const *)ptr;
+ while (len >= SIP_BLOCK_SIZE) {
+ u64 m = 0;
+ gb_memcopy(&m, data, 8);
+
+ sip->v3 ^= m;
+
+ for (isize i = 0; i < sip->c_rounds; i++) {
+ sip_compress(sip);
+ }
+
+ sip->v0 ^= m;
+
+ data += SIP_BLOCK_SIZE;
+ len -= SIP_BLOCK_SIZE;
+ }
+}
+
+void typeid_hash_context_update(TypeidHashContext *ctx, void const *ptr, isize len) {
+ GB_ASSERT(ctx->sip.is_initialized);
+ SipHashContext *sip = &ctx->sip;
+
+ u8 const *data = cast(u8 const *)ptr;
+ sip->total_length += len;
+ if (sip->last_block > 0) {
+ isize n = gb_min(SIP_BLOCK_SIZE - sip->last_block, len);
+ gb_memcopy(sip->buf + sip->last_block, data, n);
+ sip->last_block += n;
+ if (sip->last_block == SIP_BLOCK_SIZE) {
+ sip_block(sip, sip->buf, SIP_BLOCK_SIZE);
+ sip->last_block = 0;
+ }
+ data += n;
+ len -= n;
+ }
+
+ if (len >= SIP_BLOCK_SIZE) {
+ isize n = len & ~(SIP_BLOCK_SIZE-1);
+ sip_block(sip, data, n);
+ data += n;
+ len -= n;
+ }
+ if (len > 0) {
+ isize n = gb_min(SIP_BLOCK_SIZE, len);
+ gb_memcopy(sip->buf, data, n);
+ sip->last_block = n;
+ }
+}
+
+u64 typeid_hash_context_fini(TypeidHashContext *ctx) {
+ GB_ASSERT(ctx->sip.is_initialized);
+ SipHashContext *sip = &ctx->sip;
+
+ u8 tmp[SIP_BLOCK_SIZE] = {};
+ gb_memcopy(tmp, sip->buf, gb_min(sip->last_block, SIP_BLOCK_SIZE));
+ tmp[7] = u8(sip->total_length & 0xff);
+ sip_block(sip, tmp, SIP_BLOCK_SIZE);
+
+ sip->v2 ^= 0xff;
+
+ for (isize i = 0; i < sip->d_rounds; i++) {
+ sip_compress(sip);
+ }
+
+ u64 res = sip->v0 ^ sip->v1 ^ sip->v2 ^ sip->v3;
+
+ *sip = {};
+
+ return res ? res : 1;
+}
+
+
+
struct TypeWriter {
- TypeWriterProc *proc;
- void *user_data;
+ TypeWriterProc * proc;
+ void * user_data;
+ TypeidHashContext hash_ctx;
};
bool type_writer_append(TypeWriter *w, void const *ptr, isize len) {
@@ -289,13 +426,14 @@ void type_writer_destroy_string(TypeWriter *w) {
TYPE_WRITER_PROC(type_writer_hasher_writer_proc) {
- u64 *seed = cast(u64 *)w->user_data;
- *seed = fnv64a(ptr, len, *seed);
+ TypeidHashContext *ctx = cast(TypeidHashContext *)w->user_data;
+ typeid_hash_context_update(ctx, ptr, len);
return true;
}
-void type_writer_make_hasher(TypeWriter *w, u64 *hash) {
- w->user_data = hash;
+void type_writer_make_hasher(TypeWriter *w, TypeidHashContext *ctx) {
+ typeid_hash_context_init(ctx);
+ w->user_data = ctx;
w->proc = type_writer_hasher_writer_proc;
}
@@ -378,11 +516,10 @@ gb_internal u64 type_hash_canonical_type(Type *type) {
return prev_hash;
}
- u64 hash = fnv64a(nullptr, 0);
TypeWriter w = {};
- type_writer_make_hasher(&w, &hash);
+ type_writer_make_hasher(&w, &w.hash_ctx);
write_type_to_canonical_string(&w, type);
- hash = hash ? hash : 1;
+ u64 hash = typeid_hash_context_fini(&w.hash_ctx);
type->canonical_hash.store(hash, std::memory_order_relaxed);
@@ -417,7 +554,7 @@ gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity
gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) {
GB_ASSERT(e != nullptr);
- if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) {
+ if (e->kind == Entity_Procedure || e->kind == Entity_TypeName || e->kind == Entity_Variable) {
if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) {
// no prefix
return;
@@ -527,6 +664,11 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) {
} else if (s->flags & (ScopeFlag_Builtin)) {
goto write_base_name;
}
+
+ if (e->kind == Entity_TypeName) {
+ goto write_base_name;
+ }
+
gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info);
auto const print_scope_flags = [](Scope *s) {
@@ -543,7 +685,7 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) {
};
print_scope_flags(s);
- GB_PANIC("weird entity %.*s", LIT(e->token.string));
+ GB_PANIC("weird entity %.*s (%.*s)", LIT(e->token.string), LIT(entity_strings[e->kind]));
}
if (e->pkg != nullptr) {
type_writer_append(w, e->pkg->name.text, e->pkg->name.len);
@@ -744,8 +886,9 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
write_canonical_params(w, type->Struct.polymorphic_params);
}
- if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
- if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
+ if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
+ if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
+ if (type->Struct.is_all_or_none) type_writer_appendc(w, "#all_or_none");
if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align);
if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align);
if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align);
@@ -756,6 +899,14 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
if (i > 0) {
type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR);
}
+
+ if (f->flags & EntityFlags_IsSubtype) {
+ type_writer_appendc(w, "#subtype ");
+ }
+
+ if (f->flags & EntityFlag_Using) {
+ type_writer_appendc(w, "using ");
+ }
type_writer_append(w, f->token.string.text, f->token.string.len);
type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR);
write_type_to_canonical_string(w, f->type);
diff --git a/src/parser.cpp b/src/parser.cpp
index 152e55f8b..06703d643 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1230,7 +1230,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
}
gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count,
- Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy,
+ Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none,
Ast *align, Ast *min_field_align, Ast *max_field_align,
Token where_token, Array<Ast *> const &where_clauses) {
Ast *result = alloc_ast_node(f, Ast_StructType);
@@ -1240,7 +1240,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i
result->StructType.polymorphic_params = polymorphic_params;
result->StructType.is_packed = is_packed;
result->StructType.is_raw_union = is_raw_union;
- result->StructType.is_no_copy = is_no_copy;
+ result->StructType.is_all_or_none = is_all_or_none;
result->StructType.align = align;
result->StructType.min_field_align = min_field_align;
result->StructType.max_field_align = max_field_align;
@@ -2773,8 +2773,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
Token token = expect_token(f, Token_struct);
Ast *polymorphic_params = nullptr;
bool is_packed = false;
+ bool is_all_or_none = false;
bool is_raw_union = false;
- bool no_copy = false;
Ast *align = nullptr;
Ast *min_field_align = nullptr;
Ast *max_field_align = nullptr;
@@ -2802,6 +2802,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
}
is_packed = true;
+ } else if (tag.string == "all_or_none") {
+ if (is_packed) {
+ syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
+ }
+ is_all_or_none = true;
} else if (tag.string == "align") {
if (align) {
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
@@ -2856,11 +2861,6 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
}
is_raw_union = true;
- } else if (tag.string == "no_copy") {
- if (no_copy) {
- syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
- }
- no_copy = true;
} else {
syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string));
}
@@ -2872,6 +2872,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
is_packed = false;
syntax_error(token, "'#raw_union' cannot also be '#packed'");
}
+ if (is_raw_union && is_all_or_none) {
+ is_all_or_none = false;
+ syntax_error(token, "'#raw_union' cannot also be '#all_or_none'");
+ }
Token where_token = {};
Array<Ast *> where_clauses = {};
@@ -2901,7 +2905,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
parser_check_polymorphic_record_parameters(f, polymorphic_params);
- return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, min_field_align, max_field_align, where_token, where_clauses);
+ return ast_struct_type(f, token, decls, name_count,
+ polymorphic_params, is_packed, is_raw_union, is_all_or_none,
+ align, min_field_align, max_field_align,
+ where_token, where_clauses);
} break;
case Token_union: {
diff --git a/src/parser.hpp b/src/parser.hpp
index 6127468d4..71b61d95f 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -766,6 +766,7 @@ AST_KIND(_TypeBegin, "", bool) \
bool is_packed; \
bool is_raw_union; \
bool is_no_copy; \
+ bool is_all_or_none; \
}) \
AST_KIND(UnionType, "union type", struct { \
Scope *scope; \
diff --git a/src/tilde_type_info.cpp b/src/tilde_type_info.cpp
index 58e8d3087..96a101376 100644
--- a/src/tilde_type_info.cpp
+++ b/src/tilde_type_info.cpp
@@ -783,14 +783,13 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
i64 is_packed_offset = type_offset_of(tag_type, 5);
i64 is_raw_union_offset = type_offset_of(tag_type, 6);
- i64 is_no_copy_offset = type_offset_of(tag_type, 7);
- i64 custom_align_offset = type_offset_of(tag_type, 8);
+ i64 custom_align_offset = type_offset_of(tag_type, 7);
- i64 equal_offset = type_offset_of(tag_type, 9);
+ i64 equal_offset = type_offset_of(tag_type, 8);
- i64 soa_kind_offset = type_offset_of(tag_type, 10);
- i64 soa_base_type_offset = type_offset_of(tag_type, 11);
- i64 soa_len_offset = type_offset_of(tag_type, 12);
+ i64 soa_kind_offset = type_offset_of(tag_type, 9);
+ i64 soa_base_type_offset = type_offset_of(tag_type, 10);
+ i64 soa_len_offset = type_offset_of(tag_type, 11);
// TODO(bill): equal proc stuff
gb_unused(equal_offset);
@@ -825,7 +824,6 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
set_bool(m, global, offset+is_packed_offset, t->Struct.is_packed);
set_bool(m, global, offset+is_raw_union_offset, t->Struct.is_raw_union);
- set_bool(m, global, offset+is_no_copy_offset, t->Struct.is_no_copy);
set_bool(m, global, offset+custom_align_offset, t->Struct.custom_align != 0);
if (t->Struct.soa_kind != StructSoa_None) {
diff --git a/src/types.cpp b/src/types.cpp
index a1311ba5d..eb20b8edf 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -162,6 +162,7 @@ struct TypeStruct {
bool are_offsets_set : 1;
bool is_packed : 1;
bool is_raw_union : 1;
+ bool is_all_or_none : 1;
bool is_poly_specialized : 1;
std::atomic<bool> are_offsets_being_processed;
@@ -3084,9 +3085,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
break;
case Type_Struct:
- if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
- x->Struct.fields.count == y->Struct.fields.count &&
- x->Struct.is_packed == y->Struct.is_packed &&
+ if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
+ x->Struct.fields.count == y->Struct.fields.count &&
+ x->Struct.is_packed == y->Struct.is_packed &&
+ x->Struct.is_all_or_none == y->Struct.is_all_or_none &&
x->Struct.soa_kind == y->Struct.soa_kind &&
x->Struct.soa_count == y->Struct.soa_count &&
are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) {
@@ -4577,6 +4579,8 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) {
case 1:
if (field_type_) *field_type_ = t_typeid;
return 8; // id
+ default:
+ GB_PANIC("index > 1");
}
}
break;
@@ -4654,6 +4658,7 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) {
switch (index) {
case 0: t = t_rawptr; break;
case 1: t = t_typeid; break;
+ default: GB_PANIC("index > 1");
}
}
break;
@@ -4919,7 +4924,7 @@ gb_internal Type *type_internal_index(Type *t, isize index) {
case Type_Slice:
{
GB_ASSERT(index == 0 || index == 1);
- return index == 0 ? t_rawptr : t_typeid;
+ return index == 0 ? t_rawptr : t_int;
}
case Type_DynamicArray:
{
diff --git a/src/ucg/ucg.c b/src/ucg/ucg.c
index c3e270e1a..119f88805 100644
--- a/src/ucg/ucg.c
+++ b/src/ucg/ucg.c
@@ -1,6 +1,6 @@
/*
* SPDX-FileCopyrightText: (c) 2024 Feoramund
- * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-License-Identifier: zlib
*/
diff --git a/src/ucg/ucg_tables.h b/src/ucg/ucg_tables.h
index a33f9f898..f31e51773 100644
--- a/src/ucg/ucg_tables.h
+++ b/src/ucg/ucg_tables.h
@@ -1,6 +1,6 @@
/*
* SPDX-FileCopyrightText: (c) 2024 Feoramund
- * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-License-Identifier: zlib
*/
#ifndef _UCG_TABLES_INCLUDED
#define _UCG_TABLES_INCLUDED