From 6a77fc4cdd35b2ecd1c32f7c5f2e249d6e225d91 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 21 Aug 2021 23:10:21 +0100 Subject: [PATCH] Add multi-pointer types `[^]T` --- src/check_expr.cpp | 82 +++++++++++++++++++++----- src/check_type.cpp | 6 ++ src/checker.cpp | 11 ++++ src/llvm_backend_expr.cpp | 55 ++++++++++++++++++ src/llvm_backend_general.cpp | 35 +++++++++++ src/llvm_backend_type.cpp | 15 +++++ src/parser.cpp | 16 ++++- src/parser.hpp | 4 ++ src/parser_pos.cpp | 2 + src/types.cpp | 110 ++++++++++++++++++++++++----------- 10 files changed, 286 insertions(+), 50 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7c46ef4ca..68009882f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -592,10 +592,25 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type #if 1 - // TODO(bill): Should I allow this implicit conversion at all?! // rawptr <- ^T if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) { - return 5; + return 5; + } + // rawptr <- [^]T + if (are_types_identical(type, t_rawptr) && is_type_multi_pointer(src)) { + return 5; + } + // ^T <- [^]T + if (is_type_pointer(dst) && is_type_multi_pointer(src)) { + if (are_types_identical(dst->Pointer.elem, src->MultiPointer.elem)) { + return 4; + } + } + // [^]T <- ^T + if (is_type_multi_pointer(dst) && is_type_pointer(src)) { + if (are_types_identical(dst->MultiPointer.elem, src->Pointer.elem)) { + return 4; + } } #endif @@ -2392,6 +2407,15 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (is_type_pointer(src) && is_type_pointer(dst)) { return true; } + if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) { + return true; + } + if (is_type_multi_pointer(src) && is_type_pointer(dst)) { + return true; + } + if (is_type_pointer(src) && is_type_multi_pointer(dst)) { + return true; + } // uintptr <-> pointer if (is_type_uintptr(src) && is_type_pointer(dst)) { @@ -2400,16 +2424,18 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (is_type_pointer(src) && is_type_uintptr(dst)) { return true; } + if (is_type_uintptr(src) && is_type_multi_pointer(dst)) { + return true; + } + if (is_type_multi_pointer(src) && is_type_uintptr(dst)) { + return true; + } // []byte/[]u8 <-> string (not cstring) if (is_type_u8_slice(src) && (is_type_string(dst) && !is_type_cstring(dst))) { return true; } - if ((is_type_string(src) && !is_type_cstring(src)) && is_type_u8_slice(dst)) { - // if (is_type_typed(src)) { - // return true; - // } - } + // cstring -> string if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { if (operand->mode != Addressing_Constant) { @@ -2421,6 +2447,10 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (are_types_identical(src, t_cstring) && is_type_u8_ptr(dst)) { return !is_constant; } + // cstring -> [^]u8 + if (are_types_identical(src, t_cstring) && is_type_u8_multi_ptr(dst)) { + return !is_constant; + } // cstring -> rawptr if (are_types_identical(src, t_cstring) && is_type_rawptr(dst)) { return !is_constant; @@ -2430,6 +2460,10 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (is_type_u8_ptr(src) && are_types_identical(dst, t_cstring)) { return !is_constant; } + // [^]u8 -> cstring + if (is_type_u8_multi_ptr(src) && are_types_identical(dst, t_cstring)) { + return !is_constant; + } // rawptr -> cstring if (is_type_rawptr(src) && are_types_identical(dst, t_cstring)) { return !is_constant; @@ -3328,7 +3362,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { operand->type = target_type; } -bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) { +bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) { Operand operand = {Addressing_Invalid}; check_expr_with_type_hint(c, &operand, index_value, type_hint); if (operand.mode == Addressing_Invalid) { @@ -3367,7 +3401,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 if (operand.mode == Addressing_Constant && (c->state_flags & StateFlag_no_bounds_check) == 0) { BigInt i = exact_value_to_integer(operand.value).value_integer; - if (i.sign && !is_type_enum(index_type)) { + if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) { gbString expr_str = expr_to_string(operand.expr); error(operand.expr, "Index '%s' cannot be a negative value", expr_str); gb_string_free(expr_str); @@ -6102,6 +6136,13 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count, } break; + case Type_MultiPointer: + o->type = t->MultiPointer.elem; + if (o->mode != Addressing_Constant) { + o->mode = Addressing_Variable; + } + return true; + case Type_Array: *max_count = t->Array.count; if (indirection) { @@ -8133,13 +8174,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } i64 index = 0; - bool ok = check_index_value(c, false, ie->index, max_count, &index, index_type_hint); + bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint); if (is_const) { if (index < 0) { - if (max_count < 0) { - - } - gbString str = expr_to_string(o->expr); error(o->expr, "Cannot index a constant '%s'", str); error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); @@ -8206,6 +8243,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type o->type = alloc_type_slice(t->Array.elem); break; + case Type_MultiPointer: + valid = true; + o->type = type_deref(o->type); + break; + case Type_Slice: valid = true; o->type = type_deref(o->type); @@ -8262,7 +8304,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type capacity = max_count; } i64 j = 0; - if (check_index_value(c, true, nodes[i], capacity, &j)) { + if (check_index_value(c, t, true, nodes[i], capacity, &j)) { index = j; } @@ -8291,6 +8333,16 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } + if (t->kind == Type_MultiPointer && se->high != nullptr) { + /* + x[:] -> [^]T + x[i:] -> [^]T + x[:n] -> []T + x[i:n] -> []T + */ + o->type = alloc_type_slice(t->MultiPointer.elem); + } + o->mode = Addressing_Value; if (is_type_string(t) && max_count >= 0) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 867b4d7b2..3541eef61 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2525,6 +2525,12 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t return true; case_end; + case_ast_node(pt, MultiPointerType, e); + *type = alloc_type_multi_pointer(check_type(ctx, pt->type)); + set_base_type(named_type, *type); + return true; + case_end; + case_ast_node(rt, RelativeType, e); GB_ASSERT(rt->tag->kind == Ast_CallExpr); ast_node(ce, CallExpr, rt->tag); diff --git a/src/checker.cpp b/src/checker.cpp index 939872c0c..987d08e8d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1545,6 +1545,10 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->Pointer.elem); break; + case Type_MultiPointer: + add_type_info_type_internal(c, bt->MultiPointer.elem); + break; + case Type_Array: add_type_info_type_internal(c, bt->Array.elem); add_type_info_type_internal(c, alloc_type_pointer(bt->Array.elem)); @@ -1754,6 +1758,10 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->Pointer.elem); break; + case Type_MultiPointer: + add_min_dep_type_info(c, bt->MultiPointer.elem); + break; + case Type_Array: add_min_dep_type_info(c, bt->Array.elem); add_min_dep_type_info(c, alloc_type_pointer(bt->Array.elem)); @@ -1993,6 +2001,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("bounds_check_error"), str_lit("slice_expr_error_hi"), str_lit("slice_expr_error_lo_hi"), + str_lit("multi_pointer_slice_expr_error"), }; for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]); @@ -2400,6 +2409,7 @@ void init_core_type_info(Checker *c) { t_type_info_any = find_core_type(c, str_lit("Type_Info_Any")); t_type_info_typeid = find_core_type(c, str_lit("Type_Info_Type_Id")); t_type_info_pointer = find_core_type(c, str_lit("Type_Info_Pointer")); + t_type_info_multi_pointer = find_core_type(c, str_lit("Type_Info_Multi_Pointer")); t_type_info_procedure = find_core_type(c, str_lit("Type_Info_Procedure")); t_type_info_array = find_core_type(c, str_lit("Type_Info_Array")); t_type_info_enumerated_array = find_core_type(c, str_lit("Type_Info_Enumerated_Array")); @@ -2426,6 +2436,7 @@ void init_core_type_info(Checker *c) { t_type_info_any_ptr = alloc_type_pointer(t_type_info_any); t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid); t_type_info_pointer_ptr = alloc_type_pointer(t_type_info_pointer); + t_type_info_multi_pointer_ptr = alloc_type_pointer(t_type_info_multi_pointer); t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure); t_type_info_array_ptr = alloc_type_pointer(t_type_info_array); t_type_info_enumerated_array_ptr = alloc_type_pointer(t_type_info_enumerated_array); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c598fbf62..27517f7a3 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1274,6 +1274,25 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); return res; } + if (is_type_multi_pointer(src) && is_type_pointer(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + if (is_type_pointer(src) && is_type_multi_pointer(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + @@ -2838,6 +2857,21 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { return lb_addr(v); } + case Type_MultiPointer: { + lbValue multi_ptr = {}; + multi_ptr = lb_build_expr(p, ie->expr); + if (deref) { + multi_ptr = lb_emit_load(p, multi_ptr); + } + lbValue index = lb_build_expr(p, ie->index); + lbValue v = {}; + + LLVMValueRef indices[1] = {index.value}; + v.value = LLVMBuildGEP(p->builder, multi_ptr.value, indices, 1, ""); + v.type = t; + return lb_addr(v); + } + case Type_RelativeSlice: { lbAddr slice_addr = {}; if (deref) { @@ -2952,6 +2986,27 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { return slice; } + case Type_MultiPointer: { + lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); + if (se->high == nullptr) { + lbValue offset = base; + LLVMValueRef indices[1] = {low.value}; + offset.value = LLVMBuildGEP(p->builder, offset.value, indices, 1, ""); + lb_addr_store(p, res, offset); + } else { + lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + + LLVMValueRef indices[1] = {low.value}; + LLVMValueRef ptr = LLVMBuildGEP(p->builder, base.value, indices, 1, ""); + LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); + // TODO(bill): bounds_check for negative length + LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; + LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; + LLVMBuildStore(p->builder, ptr, gep0); + LLVMBuildStore(p->builder, len, gep1); + } + return res; + } case Type_Array: { Type *slice_type = alloc_type_slice(type->Array.elem); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 20b3aba25..94fe1e562 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -420,6 +420,31 @@ void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue le lb_emit_runtime_call(p, "bounds_check_error", args); } +void lb_emit_multi_pointer_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high) { + if (build_context.no_bounds_check) { + return; + } + if ((p->state_flags & StateFlag_no_bounds_check) != 0) { + return; + } + + low = lb_emit_conv(p, low, t_int); + high = lb_emit_conv(p, high, t_int); + + lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id)); + lbValue line = lb_const_int(p->module, t_i32, token.pos.line); + lbValue column = lb_const_int(p->module, t_i32, token.pos.column); + + auto args = array_make(permanent_allocator(), 5); + args[0] = file; + args[1] = line; + args[2] = column; + args[3] = low; + args[4] = high; + + lb_emit_runtime_call(p, "multi_pointer_slice_expr_error", args); +} + void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high, lbValue len, bool lower_value_used) { if (build_context.no_bounds_check) { return; @@ -810,6 +835,13 @@ LLVMTypeRef llvm_addr_type(lbValue addr_val) { lbValue lb_emit_load(lbProcedure *p, lbValue value) { GB_ASSERT(value.value != nullptr); + if (is_type_multi_pointer(value.type)) { + Type *vt = base_type(value.type); + GB_ASSERT(vt->kind == Type_MultiPointer); + Type *t = vt->MultiPointer.elem; + LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); + return lbValue{v, t}; + } GB_ASSERT(is_type_pointer(value.type)); Type *t = type_deref(value.type); LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); @@ -1568,6 +1600,9 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Pointer: return LLVMPointerType(lb_type(m, type->Pointer.elem), 0); + case Type_MultiPointer: + return LLVMPointerType(lb_type(m, type->Pointer.elem), 0); + case Type_Array: { m->internal_type_level -= 1; LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index d58ab1c77..af3fadc3c 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -40,6 +40,7 @@ lbValue lb_typeid(lbModule *m, Type *type) { if (flags & BasicFlag_Rune) kind = Typeid_Rune; } break; case Type_Pointer: kind = Typeid_Pointer; break; + case Type_MultiPointer: kind = Typeid_Multi_Pointer; break; case Type_Array: kind = Typeid_Array; break; case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; case Type_Slice: kind = Typeid_Slice; break; @@ -396,6 +397,20 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lb_emit_store(p, tag, res); break; } + case Type_MultiPointer: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr); + lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem); + + LLVMValueRef vals[1] = { + gep.value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } case Type_Array: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); i64 ez = type_size_of(t->Array.elem); diff --git a/src/parser.cpp b/src/parser.cpp index 6184a62ab..898dd4da6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -337,6 +337,9 @@ Ast *clone_ast(Ast *node) { case Ast_PointerType: n->PointerType.type = clone_ast(n->PointerType.type); break; + case Ast_MultiPointerType: + n->MultiPointerType.type = clone_ast(n->MultiPointerType.type); + break; case Ast_ArrayType: n->ArrayType.count = clone_ast(n->ArrayType.count); n->ArrayType.elem = clone_ast(n->ArrayType.elem); @@ -985,7 +988,12 @@ Ast *ast_pointer_type(AstFile *f, Token token, Ast *type) { result->PointerType.type = type; return result; } - +Ast *ast_multi_pointer_type(AstFile *f, Token token, Ast *type) { + Ast *result = alloc_ast_node(f, Ast_MultiPointerType); + result->MultiPointerType.token = token; + result->MultiPointerType.type = type; + return result; +} Ast *ast_array_type(AstFile *f, Token token, Ast *count, Ast *elem) { Ast *result = alloc_ast_node(f, Ast_ArrayType); result->ArrayType.token = token; @@ -2317,7 +2325,11 @@ Ast *parse_operand(AstFile *f, bool lhs) { case Token_OpenBracket: { Token token = expect_token(f, Token_OpenBracket); Ast *count_expr = nullptr; - if (f->curr_token.kind == Token_Question) { + if (f->curr_token.kind == Token_Pointer) { + expect_token(f, Token_Pointer); + expect_token(f, Token_CloseBracket); + return ast_multi_pointer_type(f, token, parse_type(f)); + } else if (f->curr_token.kind == Token_Question) { count_expr = ast_unary_expr(f, expect_token(f, Token_Question), nullptr); } else if (allow_token(f, Token_dynamic)) { expect_token(f, Token_CloseBracket); diff --git a/src/parser.hpp b/src/parser.hpp index 3612d5e96..1b45024b6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -604,6 +604,10 @@ AST_KIND(_TypeBegin, "", bool) \ Ast *tag; \ Ast *type; \ }) \ + AST_KIND(MultiPointerType, "multi pointer type", struct { \ + Token token; \ + Ast *type; \ + }) \ AST_KIND(ArrayType, "array type", struct { \ Token token; \ Ast *count; \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 0f2ac438a..8d164caf9 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -95,6 +95,7 @@ Token ast_token(Ast *node) { case Ast_ProcType: return node->ProcType.token; case Ast_RelativeType: return ast_token(node->RelativeType.tag); case Ast_PointerType: return node->PointerType.token; + case Ast_MultiPointerType: return node->MultiPointerType.token; case Ast_ArrayType: return node->ArrayType.token; case Ast_DynamicArrayType: return node->DynamicArrayType.token; case Ast_StructType: return node->StructType.token; @@ -312,6 +313,7 @@ Token ast_end_token(Ast *node) { case Ast_RelativeType: return ast_end_token(node->RelativeType.type); case Ast_PointerType: return ast_end_token(node->PointerType.type); + case Ast_MultiPointerType: return ast_end_token(node->MultiPointerType.type); case Ast_ArrayType: return ast_end_token(node->ArrayType.elem); case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem); case Ast_StructType: diff --git a/src/types.cpp b/src/types.cpp index b8a20173b..37a05d5a6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -192,47 +192,48 @@ struct TypeProc { bool optional_ok; }; -#define TYPE_KINDS \ - TYPE_KIND(Basic, BasicType) \ - TYPE_KIND(Named, struct { \ +#define TYPE_KINDS \ + TYPE_KIND(Basic, BasicType) \ + TYPE_KIND(Named, struct { \ String name; \ Type * base; \ Entity *type_name; /* Entity_TypeName */ \ - }) \ - TYPE_KIND(Generic, struct { \ + }) \ + TYPE_KIND(Generic, struct { \ i64 id; \ String name; \ Type * specialized; \ Scope * scope; \ Entity *entity; \ - }) \ - TYPE_KIND(Pointer, struct { Type *elem; }) \ - TYPE_KIND(Array, struct { \ + }) \ + TYPE_KIND(Pointer, struct { Type *elem; }) \ + TYPE_KIND(MultiPointer, struct { Type *elem; }) \ + TYPE_KIND(Array, struct { \ Type *elem; \ i64 count; \ Type *generic_count; \ - }) \ - TYPE_KIND(EnumeratedArray, struct { \ + }) \ + TYPE_KIND(EnumeratedArray, struct { \ Type *elem; \ Type *index; \ ExactValue min_value; \ ExactValue max_value; \ i64 count; \ TokenKind op; \ - }) \ - TYPE_KIND(Slice, struct { Type *elem; }) \ - TYPE_KIND(DynamicArray, struct { Type *elem; }) \ - TYPE_KIND(Map, struct { \ + }) \ + TYPE_KIND(Slice, struct { Type *elem; }) \ + TYPE_KIND(DynamicArray, struct { Type *elem; }) \ + TYPE_KIND(Map, struct { \ Type *key; \ Type *value; \ Type *entry_type; \ Type *generated_struct_type; \ Type *internal_type; \ Type *lookup_result_type; \ - }) \ - TYPE_KIND(Struct, TypeStruct) \ - TYPE_KIND(Union, TypeUnion) \ - TYPE_KIND(Enum, struct { \ + }) \ + TYPE_KIND(Struct, TypeStruct) \ + TYPE_KIND(Union, TypeUnion) \ + TYPE_KIND(Enum, struct { \ Array fields; \ Ast *node; \ Scope * scope; \ @@ -242,31 +243,31 @@ struct TypeProc { ExactValue max_value; \ isize min_value_index; \ isize max_value_index; \ - }) \ - TYPE_KIND(Tuple, struct { \ + }) \ + TYPE_KIND(Tuple, struct { \ Array variables; /* Entity_Variable */ \ Array offsets; \ bool are_offsets_being_processed; \ bool are_offsets_set; \ bool is_packed; \ - }) \ - TYPE_KIND(Proc, TypeProc) \ - TYPE_KIND(BitSet, struct { \ + }) \ + TYPE_KIND(Proc, TypeProc) \ + TYPE_KIND(BitSet, struct { \ Type *elem; \ Type *underlying; \ i64 lower; \ i64 upper; \ Ast * node; \ - }) \ - TYPE_KIND(SimdVector, struct { \ + }) \ + TYPE_KIND(SimdVector, struct { \ i64 count; \ Type *elem; \ - }) \ - TYPE_KIND(RelativePointer, struct { \ + }) \ + TYPE_KIND(RelativePointer, struct { \ Type *pointer_type; \ Type *base_integer; \ - }) \ - TYPE_KIND(RelativeSlice, struct { \ + }) \ + TYPE_KIND(RelativeSlice, struct { \ Type *slice_type; \ Type *base_integer; \ }) @@ -325,6 +326,7 @@ enum Typeid_Kind : u8 { Typeid_Any, Typeid_Type_Id, Typeid_Pointer, + Typeid_Multi_Pointer, Typeid_Procedure, Typeid_Array, Typeid_Enumerated_Array, @@ -605,6 +607,7 @@ gb_global Type *t_type_info_typeid = nullptr; gb_global Type *t_type_info_string = nullptr; gb_global Type *t_type_info_boolean = nullptr; gb_global Type *t_type_info_pointer = nullptr; +gb_global Type *t_type_info_multi_pointer = nullptr; gb_global Type *t_type_info_procedure = nullptr; gb_global Type *t_type_info_array = nullptr; gb_global Type *t_type_info_enumerated_array = nullptr; @@ -631,6 +634,7 @@ gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr; gb_global Type *t_type_info_boolean_ptr = nullptr; gb_global Type *t_type_info_pointer_ptr = nullptr; +gb_global Type *t_type_info_multi_pointer_ptr = nullptr; gb_global Type *t_type_info_procedure_ptr = nullptr; gb_global Type *t_type_info_array_ptr = nullptr; gb_global Type *t_type_info_enumerated_array_ptr = nullptr; @@ -779,6 +783,12 @@ Type *alloc_type_pointer(Type *elem) { return t; } +Type *alloc_type_multi_pointer(Type *elem) { + Type *t = alloc_type(Type_MultiPointer); + t->MultiPointer.elem = elem; + return t; +} + Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { if (generic_count != nullptr) { Type *t = alloc_type(Type_Array); @@ -948,10 +958,10 @@ Type *type_deref(Type *t) { if (bt == nullptr) { return nullptr; } - if (bt != nullptr && bt->kind == Type_Pointer) { + if (bt->kind == Type_Pointer) { return bt->Pointer.elem; } - if (bt != nullptr && bt->kind == Type_RelativePointer) { + if (bt->kind == Type_RelativePointer) { return type_deref(bt->RelativePointer.pointer_type); } } @@ -1084,6 +1094,8 @@ bool is_type_ordered(Type *t) { return (t->Basic.flags & BasicFlag_Ordered) != 0; case Type_Pointer: return true; + case Type_MultiPointer: + return true; } return false; } @@ -1157,6 +1169,10 @@ bool is_type_pointer(Type *t) { } return t->kind == Type_Pointer; } +bool is_type_multi_pointer(Type *t) { + t = base_type(t); + return t->kind == Type_MultiPointer; +} bool is_type_tuple(Type *t) { t = base_type(t); return t->kind == Type_Tuple; @@ -1259,6 +1275,13 @@ bool is_type_u8_ptr(Type *t) { } return false; } +bool is_type_u8_multi_ptr(Type *t) { + t = base_type(t); + if (t->kind == Type_MultiPointer) { + return is_type_u8(t->Slice.elem); + } + return false; +} bool is_type_rune_array(Type *t) { t = base_type(t); if (t->kind == Type_Array) { @@ -1348,7 +1371,8 @@ bool is_type_union_maybe_pointer(Type *t) { t = base_type(t); if (t->kind == Type_Union && t->Union.maybe) { if (t->Union.variants.count == 1) { - return is_type_pointer(t->Union.variants[0]); + Type *v = t->Union.variants[0]; + return is_type_pointer(v) || is_type_multi_pointer(v); } } return false; @@ -1360,7 +1384,7 @@ bool is_type_union_maybe_pointer_original_alignment(Type *t) { if (t->kind == Type_Union && t->Union.maybe) { if (t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; - if (is_type_pointer(v)) { + if (is_type_pointer(v) || is_type_multi_pointer(v)) { return type_align_of(v) == type_align_of(t); } } @@ -1614,6 +1638,8 @@ bool is_type_indexable(Type *t) { case Type_DynamicArray: case Type_Map: return true; + case Type_MultiPointer: + return true; case Type_EnumeratedArray: return true; case Type_RelativeSlice: @@ -1836,6 +1862,7 @@ bool type_has_nil(Type *t) { case Type_Slice: case Type_Proc: case Type_Pointer: + case Type_MultiPointer: case Type_DynamicArray: case Type_Map: return true; @@ -1890,6 +1917,8 @@ bool is_type_comparable(Type *t) { return true; case Type_Pointer: return true; + case Type_MultiPointer: + return true; case Type_Enum: return is_type_comparable(core_type(t)); case Type_EnumeratedArray: @@ -1955,6 +1984,7 @@ bool is_type_simple_compare(Type *t) { return false; case Type_Pointer: + case Type_MultiPointer: case Type_Proc: case Type_BitSet: return true; @@ -2157,6 +2187,12 @@ bool are_types_identical(Type *x, Type *y) { } break; + case Type_MultiPointer: + if (y->kind == Type_MultiPointer) { + return are_types_identical(x->MultiPointer.elem, y->MultiPointer.elem); + } + break; + case Type_Named: if (y->kind == Type_Named) { return x->Named.type_name == y->Named.type_name; @@ -3139,6 +3175,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) { case Type_Pointer: return build_context.word_size; + case Type_MultiPointer: + return build_context.word_size; + case Type_Array: { i64 count, align, size, alignment; count = t->Array.count; @@ -3509,6 +3548,11 @@ gbString write_type_to_string(gbString str, Type *type) { str = write_type_to_string(str, type->Pointer.elem); break; + case Type_MultiPointer: + str = gb_string_appendc(str, "[^]"); + str = write_type_to_string(str, type->Pointer.elem); + break; + case Type_EnumeratedArray: str = gb_string_append_rune(str, '['); str = write_type_to_string(str, type->EnumeratedArray.index);