diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index baa0dc696..47a40b2e2 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -8,6 +8,7 @@ import "core:types" import "core:strconv" +@(private) DEFAULT_BUFFER_SIZE :: 1<<12; String_Buffer :: distinct [dynamic]byte; @@ -238,7 +239,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) { case runtime.Type_Info_Named: write_string(buf, info.name); case runtime.Type_Info_Integer: - a := any{typeid = typeid_of(ti)}; + a := any{id = ti.id}; switch in a { case int: write_string(buf, "int"); case uint: write_string(buf, "uint"); @@ -262,7 +263,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) { write_string(buf, "string"); } case runtime.Type_Info_Boolean: - a := any{typeid = typeid_of(ti)}; + a := any{id = ti.id}; switch in a { case bool: write_string(buf, "bool"); case: @@ -462,7 +463,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) { ok := true; if arg_index < len(args) { arg := args[arg_index]; - arg.typeid = runtime.typeid_base(arg.typeid); + arg.id = runtime.typeid_base(arg.id); switch i in arg { case int: num = i; case i8: num = int(i); @@ -486,8 +487,8 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) { write_string(buf, "%!"); write_rune(buf, verb); write_byte(buf, '('); - if arg.typeid != nil { - write_typeid(buf, arg.typeid); + if arg.id != nil { + write_typeid(buf, arg.id); write_byte(buf, '='); fmt_value(fi, arg, 'v'); } else { @@ -721,8 +722,8 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) { } enum_value_to_string :: proc(v: any) -> (string, bool) { - v.typeid = runtime.typeid_base(v.typeid); - type_info := type_info_of(v.typeid); + v.id = runtime.typeid_base(v.id); + type_info := type_info_of(v.id); switch e in type_info.variant { case: return "", false; @@ -746,7 +747,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) { return "", false; } - a := any{v.data, typeid_of(runtime.type_info_base(e.base))}; + a := any{v.data, runtime.type_info_base(e.base).id}; switch v in a { case rune: return get_str(v, e); case i8: return get_str(v, e); @@ -781,19 +782,19 @@ string_to_enum_value :: proc(T: type, s: string) -> (T, bool) { } fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { - if v.typeid == nil || v.data == nil { + if v.id == nil || v.data == nil { write_string(fi.buf, ""); return; } - type_info := type_info_of(v.typeid); + type_info := type_info_of(v.id); switch e in type_info.variant { case: fmt_bad_verb(fi, verb); case runtime.Type_Info_Enum: switch verb { case: fmt_bad_verb(fi, verb); case 'd', 'f': - fmt_arg(fi, any{v.data, typeid_of(runtime.type_info_base(e.base))}, verb); + fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, verb); case 's', 'v': str, ok := enum_value_to_string(v); if !ok do str = "!%(BAD ENUM VALUE)"; @@ -823,11 +824,11 @@ enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 { } fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") { - type_info := type_info_of(v.typeid); + type_info := type_info_of(v.id); switch info in type_info.variant { case runtime.Type_Info_Named: val := v; - val.typeid = info.base.id; + val.id = info.base.id; fmt_bit_set(fi, val, info.name); case runtime.Type_Info_Bit_Set: @@ -877,11 +878,11 @@ fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") { } } fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") { - type_info := type_info_of(v.typeid); + type_info := type_info_of(v.id); switch info in type_info.variant { case runtime.Type_Info_Named: val := v; - val.typeid = info.base.id; + val.id = info.base.id; fmt_bit_field(fi, val, info.name); case runtime.Type_Info_Bit_Field: data: u64 = 0; @@ -923,12 +924,12 @@ fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") { } fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { - if v.data == nil || v.typeid == nil { + if v.data == nil || v.id == nil { write_string(fi.buf, ""); return; } - type_info := type_info_of(v.typeid); + type_info := type_info_of(v.id); switch info in type_info.variant { case runtime.Type_Info_Named: switch b in info.base.variant { @@ -964,7 +965,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, "any{}"); } else { data := rawptr(uintptr(v.data) + b.offsets[i]); - fmt_arg(fi, any{data, typeid_of(t)}, 'v'); + fmt_arg(fi, any{data, t.id}, 'v'); } if hash do write_string(fi.buf, ",\n"); @@ -978,7 +979,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { case runtime.Type_Info_Bit_Field: fmt_bit_field(fi, v); case: - fmt_value(fi, any{v.data, typeid_of(info.base)}, verb); + fmt_value(fi, any{v.data, info.base.id}, verb); } case runtime.Type_Info_Boolean: fmt_arg(fi, v, verb); @@ -989,7 +990,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { case runtime.Type_Info_String: fmt_arg(fi, v, verb); case runtime.Type_Info_Pointer: - if v.typeid == typeid_of(^runtime.Type_Info) { + if v.id == typeid_of(^runtime.Type_Info) { write_type(fi.buf, (^^runtime.Type_Info)(v.data)^); } else { fmt_pointer(fi, (^rawptr)(v.data)^, verb); @@ -1002,7 +1003,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if i > 0 do write_string(fi.buf, ", "); data := uintptr(v.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); } case runtime.Type_Info_Dynamic_Array: @@ -1013,7 +1014,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if i > 0 do write_string(fi.buf, ", "); data := uintptr(array.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); } case runtime.Type_Info_Slice: @@ -1024,7 +1025,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if i > 0 do write_string(fi.buf, ", "); data := uintptr(slice.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); } case runtime.Type_Info_Map: @@ -1057,13 +1058,13 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, header.key.str); } else { fi := Fmt_Info{buf = fi.buf}; - fmt_arg(&fi, any{rawptr(&header.key.hash), typeid_of(info.key)}, 'v'); + fmt_arg(&fi, any{rawptr(&header.key.hash), info.key.id}, 'v'); } write_string(fi.buf, "="); value := data + entry_type.offsets[2]; - fmt_arg(fi, any{rawptr(value), typeid_of(info.value)}, 'v'); + fmt_arg(fi, any{rawptr(value), info.value.id}, 'v'); } } @@ -1098,14 +1099,14 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_string(fi.buf, "any{}"); } else { data := uintptr(v.data) + info.offsets[i]; - fmt_arg(fi, any{rawptr(data), typeid_of(t)}, 'v'); + fmt_arg(fi, any{rawptr(data), t.id}, 'v'); } if hash do write_string(fi.buf, ",\n"); } case runtime.Type_Info_Union: tag_ptr := uintptr(v.data) + info.tag_offset; - tag_any := any{rawptr(tag_ptr), typeid_of(info.tag_type)}; + tag_any := any{rawptr(tag_ptr), info.tag_type.id}; tag: i64 = -1; switch i in tag_any { @@ -1123,7 +1124,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if v.data == nil || tag == 0 { write_string(fi.buf, "nil"); } else { - id := typeid_of(info.variants[tag-1]); + id := info.variants[tag-1].id; fmt_arg(fi, any{v.data, id}, verb); } @@ -1135,7 +1136,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if ptr == nil { write_string(fi.buf, "nil"); } else { - write_typeid(fi.buf, v.typeid); + write_typeid(fi.buf, v.id); write_string(fi.buf, " @ "); fmt_pointer(fi, ptr, 'p'); } @@ -1177,7 +1178,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { fi.arg = arg; if verb == 'T' { - ti := type_info_of(arg.typeid); + ti := type_info_of(arg.id); switch a in arg { case ^runtime.Type_Info: ti = a; } @@ -1186,7 +1187,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { } base_arg := arg; - base_arg.typeid = runtime.typeid_base(base_arg.typeid); + base_arg.id = runtime.typeid_base(base_arg.id); switch a in base_arg { case bool: fmt_bool(fi, bool(a), verb); case b8: fmt_bool(fi, bool(a), verb); @@ -1234,7 +1235,7 @@ sbprint :: proc(buf: ^String_Buffer, args: ..any) -> string { fi.buf = buf; for arg, i in args { - is_string := arg != nil && types.is_string(type_info_of(arg.typeid)); + is_string := arg != nil && types.is_string(type_info_of(arg.id)); if i > 0 && !is_string && !prev_string { write_byte(buf, ' '); } diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 5e7cc6695..d3825f3b4 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -111,7 +111,7 @@ ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte { } any_to_bytes :: proc "contextless" (val: any) -> []byte { - ti := type_info_of(val.typeid); + ti := type_info_of(val.id); size := ti != nil ? ti.size : 0; return transmute([]byte)Raw_Slice{val.data, size}; } diff --git a/core/mem/raw.odin b/core/mem/raw.odin index 9d778a72b..0fb45d6a0 100644 --- a/core/mem/raw.odin +++ b/core/mem/raw.odin @@ -1,8 +1,8 @@ package mem Raw_Any :: struct { - data: rawptr, - typeid: typeid, + data: rawptr, + id: typeid, } Raw_String :: struct { diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 7d1f8a9f6..fb428d8fe 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -268,10 +268,6 @@ type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_In return base; } -__typeid_of :: proc "contextless" (ti: ^Type_Info) -> typeid { - if ti == nil do return nil; - return ti.id; -} __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info { data := transmute(Typeid_Bit_Field)id; n := int(data.index); @@ -284,11 +280,11 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info { typeid_base :: proc "contextless" (id: typeid) -> typeid { ti := type_info_of(id); ti = type_info_base(ti); - return typeid_of(ti); + return ti.id; } typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid { ti := type_info_base_without_enum(type_info_of(id)); - return typeid_of(ti); + return ti.id; } @@ -365,6 +361,23 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E { return res; } +@(builtin) +unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) { + runtime.bounds_check_error_loc(loc, index, len(array)); + n := len(array)-1; + if index != n { + array[index] = array[n]; + } + pop(array); +} + +@(builtin) +ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) { + runtime.bounds_check_error_loc(loc, index, len(array)); + copy(array[index:], array[index+1:]); + pop(array); +} + @(builtin) clear :: proc[clear_dynamic_array, clear_map]; diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 141058647..5b1c6b434 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -63,7 +63,7 @@ __print_type :: proc(fd: os.Handle, ti: ^Type_Info) { case Type_Info_Named: os.write_string(fd, info.name); case Type_Info_Integer: - a := any{typeid = typeid_of(ti)}; + a := any{id = ti.id}; switch _ in a { case int: os.write_string(fd, "int"); case uint: os.write_string(fd, "uint"); @@ -83,7 +83,7 @@ __print_type :: proc(fd: os.Handle, ti: ^Type_Info) { case Type_Info_String: os.write_string(fd, "string"); case Type_Info_Boolean: - a := any{typeid = typeid_of(ti)}; + a := any{id = ti.id}; switch _ in a { case bool: os.write_string(fd, "bool"); case: diff --git a/src/array.cpp b/src/array.cpp index 1d3ceafed..b9bc8bb0b 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -24,21 +24,27 @@ struct Array { } }; -template void array_init (Array *array, gbAllocator const &a); -template void array_init (Array *array, gbAllocator const &a, isize count); -template void array_init (Array *array, gbAllocator const &a, isize count, isize capacity); -template Array array_make (gbAllocator const &a); -template Array array_make (gbAllocator const &a, isize count); -template Array array_make (gbAllocator const &a, isize count, isize capacity); -template Array array_make_from_ptr(T *data, isize count, isize capacity); -template void array_free (Array *array); -template void array_add (Array *array, T const &t); -template T array_pop (Array *array); -template void array_clear (Array *array); -template void array_reserve (Array *array, isize capacity); -template void array_resize (Array *array, isize count); -template void array_set_capacity (Array *array, isize capacity); -template Array array_slice (Array const &array, isize lo, isize hi); +template void array_init (Array *array, gbAllocator const &a); +template void array_init (Array *array, gbAllocator const &a, isize count); +template void array_init (Array *array, gbAllocator const &a, isize count, isize capacity); +template Array array_make (gbAllocator const &a); +template Array array_make (gbAllocator const &a, isize count); +template Array array_make (gbAllocator const &a, isize count, isize capacity); +template Array array_make_from_ptr (T *data, isize count, isize capacity); +template void array_free (Array *array); +template void array_add (Array *array, T const &t); +template T array_pop (Array *array); +template void array_clear (Array *array); +template void array_reserve (Array *array, isize capacity); +template void array_resize (Array *array, isize count); +template void array_set_capacity (Array *array, isize capacity); +template Array array_slice (Array const &array, isize lo, isize hi); + + +template void array_ordered_remove (Array *array, isize index); +template void array_unordered_remove(Array *array, isize index); + + template T *array_end_ptr(Array *array) { @@ -201,6 +207,27 @@ gb_inline Array array_slice(Array const &array, isize lo, isize hi) { } return out; } +template +void array_ordered_remove(Array *array, isize index) { + GB_ASSERT(0 <= index && index < array->count); + + isize bytes = (gb_size_of(T)*n) * (array->count-(index+1)); + gb_memmove(array->data+index, array->data+index+1, bytes); + array->count -= 1; +} + +template +void array_unordered_remove(Array *array, isize index) { + GB_ASSERT(0 <= index && index < array->count); + + isize n = array->count-1; + if (index != n) { + gb_memmove(array->data+index, array->data+n, gb_size_of(T)); + } + array_pop(array); +} + + #endif diff --git a/src/check_decl.cpp b/src/check_decl.cpp index efcbbe1d6..9b571867f 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -232,12 +232,11 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) GB_ASSERT(e->type == nullptr); DeclInfo *decl = decl_info_of_entity(e); - if (decl != nullptr && total_attribute_count(decl) > 0) { - error(decl->attributes[0], "Attributes are not allowed on type declarations"); + if (decl != nullptr) { + check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr); } - bool is_distinct = is_type_distinct(type_expr); Ast *te = remove_type_alias_clutter(type_expr); e->type = t_invalid; @@ -254,6 +253,11 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) check_type_path_pop(ctx); named->Named.base = base_type(bt); + + if (is_distinct && is_type_typeid(e->type)) { + error(type_expr, "'distinct' cannot be applied to 'typeid'"); + is_distinct = false; + } if (!is_distinct) { e->type = bt; named->Named.base = bt; @@ -393,8 +397,8 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, DeclInfo *decl = decl_info_of_entity(e); - if (decl != nullptr && total_attribute_count(decl) > 0) { - error(decl->attributes[0], "Attributes are not allowed on constant value declarations"); + if (decl != nullptr) { + check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 93f2f5fe9..f26e487b8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3200,10 +3200,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 add_type_info_type(c, t); t = base_type(t); - if (is_operand_value(o) && are_types_identical(t, t_type_info_ptr)) { - add_package_dependency(c, "runtime", "__typeid_of"); - } else if (o.mode != Addressing_Type) { - error(expr, "Expected a type or type info for 'typeid_of'"); + if (o.mode != Addressing_Type) { + error(expr, "Expected a type for 'typeid_of'"); return false; } @@ -6069,6 +6067,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } case_end; + case Ast_TypeidType: case Ast_TypeType: case Ast_PolyType: case Ast_ProcType: @@ -6077,7 +6076,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Ast_DynamicArrayType: case Ast_StructType: case Ast_UnionType: - // case Ast_RawUnionType: case Ast_EnumType: case Ast_MapType: o->mode = Addressing_Type; @@ -6512,6 +6510,14 @@ gbString write_expr_to_string(gbString str, Ast *node) { } case_end; + case_ast_node(tt, TypeidType, node); + str = gb_string_appendc(str, "typeid"); + if (tt->specialization) { + str = gb_string_appendc(str, "/"); + str = write_expr_to_string(str, tt->specialization); + } + case_end; + case_ast_node(pt, ProcType, node); str = gb_string_appendc(str, "proc("); str = write_expr_to_string(str, pt->params); diff --git a/src/check_type.cpp b/src/check_type.cpp index b5c1d7120..2eff33922 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1190,6 +1190,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is if (specialization == t_invalid){ specialization = nullptr; } + // warning(type_expr, "'type' parameters are deprecated, please use a polymorphic identifier with a type of 'typeid'. For example, '$T: typeid'"); if (operands != nullptr) { detemine_type_from_operand = true; @@ -1263,10 +1264,30 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is for_array(j, p->names) { Ast *name = p->names[j]; + + bool is_poly_name = false; + + switch (name->kind) { + case Ast_Ident: + break; + case Ast_PolyType: + GB_ASSERT(name->PolyType.specialization == nullptr); + is_poly_name = true; + name = name->PolyType.type; + break; + } if (!ast_node_expect(name, Ast_Ident)) { continue; } + if (is_poly_name) { + if (type != nullptr && is_type_typeid(type)) { + is_type_param = true; + } else { + error(name, "Polymorphic names are not yet supported for non-typeid parameters"); + } + } + Entity *param = nullptr; if (is_type_param) { if (operands != nullptr) { @@ -2022,6 +2043,14 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t return check_type_internal(ctx, dt->type, type, named_type); case_end; + case_ast_node(tt, TypeidType, e); + e->tav.mode = Addressing_Type; + e->tav.type = t_typeid; + *type = t_typeid; + set_base_type(named_type, *type); + return true; + case_end; + case_ast_node(pt, PolyType, e); Ast *ident = pt->type; if (ident->kind != Ast_Ident) { diff --git a/src/checker.cpp b/src/checker.cpp index a4635b215..ff5375a07 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1367,7 +1367,6 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { for_array(i, c->info.definitions) { Entity *e = c->info.definitions[i]; - // if (e->scope->is_global && !is_type_poly_proc(e->type)) { // TODO(bill): is the check enough? if (e->scope == builtin_pkg->scope) { // TODO(bill): is the check enough? if (e->type == nullptr) { add_dependency_to_set(c, e); @@ -1806,6 +1805,14 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) { return false; } +DECL_ATTRIBUTE_PROC(const_decl_attribute) { + if (name == "private") { + // NOTE(bill): Handled elsewhere `check_collect_value_decl` + return true; + } + return false; +} + @@ -2025,6 +2032,49 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { ast_node(vd, ValueDecl, decl); + bool entity_is_private = false; + for_array(i, vd->attributes) { + Ast *attr = vd->attributes[i]; + if (attr->kind != Ast_Attribute) continue; + auto *elems = &attr->Attribute.elems; + for (isize j = 0; j < elems->count; j++) { + Ast *elem = (*elems)[j]; + String name = {}; + Ast *value = nullptr; + switch (elem->kind) { + case_ast_node(i, Ident, elem); + name = i->token.string; + case_end; + case_ast_node(fv, FieldValue, elem); + GB_ASSERT(fv->field->kind == Ast_Ident); + name = fv->field->Ident.token.string; + value = fv->value; + case_end; + default: + continue; + } + + if (name == "private") { + if (value != nullptr) { + error(value, "'%.*s' does not expect a value", LIT(name)); + } + + if (entity_is_private) { + error(elem, "Previous declaration of '%.*s'", LIT(name)); + } else { + entity_is_private = true; + } + array_unordered_remove(elems, j); + j -= 1; + } + } + } + + if (entity_is_private && !(c->scope->flags&ScopeFlag_File)) { + error(decl, "Attribute 'private' is not allowed on a non file scope entity"); + } + + if (vd->is_mutable) { if (!(c->scope->flags&ScopeFlag_File)) { // NOTE(bill): local scope -> handle later and in order @@ -2044,6 +2094,10 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { Entity *e = alloc_entity_variable(c->scope, name->Ident.token, nullptr, false); e->identifier = name; + if (entity_is_private) { + e->flags |= EntityFlag_NotExported; + } + if (vd->is_using) { vd->is_using = false; // NOTE(bill): This error will be only caught once error(name, "'using' is not allowed at the file scope"); @@ -2145,6 +2199,10 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { } e->identifier = name; + if (entity_is_private) { + e->flags |= EntityFlag_NotExported; + } + if (vd->is_using) { if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) { d->is_using = true; diff --git a/src/entity.cpp b/src/entity.cpp index 85e768f2c..2dd4a4be0 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -47,6 +47,7 @@ enum EntityFlag { EntityFlag_PolyConst = 1<<13, EntityFlag_NotExported = 1<<14, + EntityFlag_CVarArg = 1<<20, EntityFlag_AutoCast = 1<<21, }; @@ -113,9 +114,6 @@ struct Entity { String link_prefix; bool is_foreign; bool is_export; - - // bool default_is_nil; - // bool default_is_location; bool is_immutable; } Variable; struct { diff --git a/src/ir.cpp b/src/ir.cpp index 002fdcca3..c36fc4d6d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5159,7 +5159,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { for_array(i, ce->args) { Ast *arg = ce->args[i]; TypeAndValue tav = type_and_value_of_expr(arg); - GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s", expr_to_string(arg)); + GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(arg), expr_to_string(expr)); GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg)); Type *at = tav.type; if (at->kind == Type_Tuple) { @@ -5973,7 +5973,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); String field_names[2] = { str_lit("data"), - str_lit("typeid"), + str_lit("id"), }; Type *field_types[2] = { t_rawptr, diff --git a/src/parser.cpp b/src/parser.cpp index b160082ae..f30728682 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -78,6 +78,7 @@ Token ast_token(Ast *node) { return ast_token(node->UnionField.name); case Ast_TypeType: return node->TypeType.token; + case Ast_TypeidType: return node->TypeidType.token; case Ast_HelperType: return node->HelperType.token; case Ast_DistinctType: return node->DistinctType.token; case Ast_PolyType: return node->PolyType.token; @@ -307,6 +308,9 @@ Ast *clone_ast(Ast *node) { n->UnionField.list = clone_ast(n->UnionField.list); break; + case Ast_TypeidType: + n->TypeidType.specialization = clone_ast(n->TypeidType.specialization); + break; case Ast_TypeType: n->TypeType.specialization = clone_ast(n->TypeType.specialization); break; @@ -409,7 +413,7 @@ void syntax_error(Ast *node, char *fmt, ...) { bool ast_node_expect(Ast *node, AstKind kind) { if (node->kind != kind) { - syntax_error(node, "Expected %.*s, got %.*s", LIT(ast_strings[node->kind])); + error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind])); return false; } return true; @@ -824,6 +828,13 @@ Ast *ast_union_field(AstFile *f, Ast *name, Ast *list) { } +Ast *ast_typeid_type(AstFile *f, Token token, Ast *specialization) { + Ast *result = alloc_ast_node(f, Ast_TypeidType); + result->TypeidType.token = token; + result->TypeidType.specialization = specialization; + return result; +} + Ast *ast_type_type(AstFile *f, Token token, Ast *specialization) { Ast *result = alloc_ast_node(f, Ast_TypeType); result->TypeType.token = token; @@ -1354,10 +1365,14 @@ Ast * parse_block_stmt(AstFile *f, b32 is_when); -Ast *parse_ident(AstFile *f) { +Ast *parse_ident(AstFile *f, bool allow_poly_names=false) { Token token = f->curr_token; if (token.kind == Token_Ident) { advance_token(f); + } else if (allow_poly_names && token.kind == Token_Dollar) { + Token dollar = token; + Ast *name = ast_ident(f, expect_token(f, Token_Ident)); + return ast_poly_type(f, dollar, name, nullptr); } else { token.string = str_lit("_"); expect_token(f, Token_Ident); @@ -1752,6 +1767,15 @@ Ast *parse_operand(AstFile *f, bool lhs) { return ast_poly_type(f, token, type, specialization); } break; + case Token_typeid: { + Token token = expect_token(f, Token_typeid); + // Ast *specialization = nullptr; + // if (allow_token(f, Token_Quo)) { + // specialization = parse_type(f); + // } + return ast_typeid_type(f, token, nullptr); + } break; + case Token_type_of: { Ast *i = ast_implicit(f, expect_token(f, Token_type_of)); Ast *type = parse_call_expr(f, i); @@ -2324,11 +2348,11 @@ Array parse_rhs_expr_list(AstFile *f) { return parse_expr_list(f, false); } -Array parse_ident_list(AstFile *f) { +Array parse_ident_list(AstFile *f, bool allow_poly_names) { auto list = array_make(heap_allocator()); for (;;) { - array_add(&list, parse_ident(f)); + array_add(&list, parse_ident(f, allow_poly_names)); if (f->curr_token.kind != Token_Comma || f->curr_token.kind == Token_EOF) { break; @@ -2660,12 +2684,18 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) { if (field->type->kind == Ast_TypeType || field->type->kind == Ast_PolyType) { is_generic = true; - break; + goto end; + } + for_array(j, field->names) { + Ast *name = field->names[j]; + if (name->kind == Ast_PolyType) { + is_generic = true; + goto end; + } } } } - - +end: return ast_proc_type(f, proc_token, params, results, tags, cc, is_generic); } @@ -2805,7 +2835,7 @@ struct AstAndFlags { u32 flags; }; -Array convert_to_ident_list(AstFile *f, Array list, bool ignore_flags) { +Array convert_to_ident_list(AstFile *f, Array list, bool ignore_flags, bool allow_poly_names) { auto idents = array_make(heap_allocator(), 0, list.count); // Convert to ident list for_array(i, list) { @@ -2821,6 +2851,20 @@ Array convert_to_ident_list(AstFile *f, Array list, bool ign case Ast_Ident: case Ast_BadExpr: break; + + case Ast_PolyType: + if (allow_poly_names) { + if (ident->PolyType.specialization == nullptr) { + syntax_error(ident, "Polymorphic identifiers are not yet supported"); + break; + } else { + syntax_error(ident, "Expected a polymorphic identifier without any specialization"); + } + } else { + syntax_error(ident, "Expected a non-polymorphic identifier"); + } + /*fallthrough*/ + default: syntax_error(ident, "Expected an identifier"); ident = ast_ident(f, blank_token); @@ -2891,6 +2935,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi auto list = array_make(heap_allocator()); defer (array_free(&list)); + bool allow_poly_names = allow_type_token; + isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; bool seen_ellipsis = false; @@ -2915,7 +2961,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi if (f->curr_token.kind == Token_Colon) { - Array names = convert_to_ident_list(f, list, true); // Copy for semantic reasons + Array names = convert_to_ident_list(f, list, true, allow_poly_names); // Copy for semantic reasons if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); } @@ -2971,7 +3017,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi CommentGroup *docs = f->lead_comment; u32 set_flags = parse_field_prefixes(f); - Array names = parse_ident_list(f); + Array names = parse_ident_list(f, allow_poly_names); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); break; diff --git a/src/parser.hpp b/src/parser.hpp index 0cc77d2cc..c4c161864 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -418,6 +418,10 @@ AST_KIND(_DeclEnd, "", bool) \ Ast *list; \ }) \ AST_KIND(_TypeBegin, "", bool) \ + AST_KIND(TypeidType, "typeid", struct { \ + Token token; \ + Ast *specialization; \ + }) \ AST_KIND(TypeType, "type", struct { \ Token token; \ Ast *specialization; \ diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 47bff66ed..63b004453 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_foreign, "foreign"), \ TOKEN_KIND(Token_package, "package"), \ TOKEN_KIND(Token_type, "type"), \ + TOKEN_KIND(Token_typeid, "typeid"), \ TOKEN_KIND(Token_when, "when"), \ TOKEN_KIND(Token_if, "if"), \ TOKEN_KIND(Token_else, "else"), \ diff --git a/src/types.cpp b/src/types.cpp index 62db34a60..cb487e179 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1794,17 +1794,17 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty // IMPORTANT TODO(bill): Should these members be available to should I only allow them with // `Raw_Any` type? String data_str = str_lit("data"); - String typeid_str = str_lit("typeid"); + String id_str = str_lit("id"); gb_local_persist Entity *entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0); - gb_local_persist Entity *entity__any_typeid = alloc_entity_field(nullptr, make_token_ident(typeid_str), t_typeid, false, 1); + gb_local_persist Entity *entity__any_id = alloc_entity_field(nullptr, make_token_ident(id_str), t_typeid, false, 1); if (field_name == data_str) { selection_add_index(&sel, 0); sel.entity = entity__any_data; return sel; - } else if (field_name == typeid_str) { + } else if (field_name == id_str) { selection_add_index(&sel, 1); - sel.entity = entity__any_typeid; + sel.entity = entity__any_id; return sel; } #endif