diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2021-08-22 11:50:47 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-22 11:50:47 +0100 |
| commit | d3fee9d76172172a0f8a70b96938dff45f3dd7e6 (patch) | |
| tree | e3ccf349254e041a97cb8e5c5860f2b39eb3e46d | |
| parent | 93b5befe45b6464f30f7a9404d1db2d84edf201f (diff) | |
| parent | 36a6805b7cdb8b5e4014b03756f969ce6548ff73 (diff) | |
Merge pull request #1093 from odin-lang/multi-pointers
Multi Pointers `[^]T`
| -rw-r--r-- | core/encoding/json/marshal.odin | 3 | ||||
| -rw-r--r-- | core/fmt/fmt.odin | 42 | ||||
| -rw-r--r-- | core/odin/ast/ast.odin | 8 | ||||
| -rw-r--r-- | core/odin/ast/clone.odin | 2 | ||||
| -rw-r--r-- | core/odin/ast/walk.odin | 2 | ||||
| -rw-r--r-- | core/odin/doc-format/doc_format.odin | 2 | ||||
| -rw-r--r-- | core/odin/parser/parser.odin | 30 | ||||
| -rw-r--r-- | core/reflect/reflect.odin | 11 | ||||
| -rw-r--r-- | core/reflect/types.odin | 60 | ||||
| -rw-r--r-- | core/runtime/core.odin | 7 | ||||
| -rw-r--r-- | core/runtime/error_checks.odin | 18 | ||||
| -rw-r--r-- | core/runtime/print.odin | 3 | ||||
| -rw-r--r-- | src/check_expr.cpp | 98 | ||||
| -rw-r--r-- | src/check_type.cpp | 6 | ||||
| -rw-r--r-- | src/checker.cpp | 11 | ||||
| -rw-r--r-- | src/docs_format.cpp | 1 | ||||
| -rw-r--r-- | src/docs_writer.cpp | 4 | ||||
| -rw-r--r-- | src/llvm_backend_expr.cpp | 56 | ||||
| -rw-r--r-- | src/llvm_backend_general.cpp | 35 | ||||
| -rw-r--r-- | src/llvm_backend_type.cpp | 15 | ||||
| -rw-r--r-- | src/parser.cpp | 16 | ||||
| -rw-r--r-- | src/parser.hpp | 4 | ||||
| -rw-r--r-- | src/parser_pos.cpp | 2 | ||||
| -rw-r--r-- | src/types.cpp | 110 |
24 files changed, 455 insertions, 91 deletions
diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 9295e647f..d9a674d33 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -139,6 +139,9 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { case runtime.Type_Info_Pointer: return .Unsupported_Type; + case runtime.Type_Info_Multi_Pointer: + return .Unsupported_Type; + case runtime.Type_Info_Procedure: return .Unsupported_Type; diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 092726a2f..7a5e85354 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1574,6 +1574,48 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_pointer(fi, ptr, verb); } + case runtime.Type_Info_Multi_Pointer: + ptr := (^rawptr)(v.data)^; + if verb != 'p' && info.elem != nil { + a := any{ptr, info.elem.id}; + + elem := runtime.type_info_base(info.elem); + if elem != nil { + #partial switch e in elem.variant { + case runtime.Type_Info_Array, + runtime.Type_Info_Slice, + runtime.Type_Info_Dynamic_Array, + runtime.Type_Info_Map: + if ptr == nil { + io.write_string(fi.writer, "<nil>"); + return; + } + if fi.record_level < 1 { + fi.record_level += 1; + defer fi.record_level -= 1; + io.write_byte(fi.writer, '&'); + fmt_value(fi, a, verb); + return; + } + + case runtime.Type_Info_Struct, + runtime.Type_Info_Union: + if ptr == nil { + io.write_string(fi.writer, "<nil>"); + return; + } + if fi.record_level < 1 { + fi.record_level += 1; + defer fi.record_level -= 1; + io.write_byte(fi.writer, '&'); + fmt_value(fi, a, verb); + return; + } + } + } + } + fmt_pointer(fi, ptr, verb); + case runtime.Type_Info_Array: if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { s := strings.string_from_ptr((^byte)(v.data), info.count); diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 9d41a0adc..10bc538d3 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -656,6 +656,14 @@ Pointer_Type :: struct { elem: ^Expr, } +Multi_Pointer_Type :: struct { + using node: Expr, + open: tokenizer.Pos, + pointer: tokenizer.Pos, + close: tokenizer.Pos, + elem: ^Expr, +} + Array_Type :: struct { using node: Expr, open: tokenizer.Pos, diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index e80a4d05f..9af4b3941 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -251,6 +251,8 @@ clone_node :: proc(node: ^Node) -> ^Node { r.results = auto_cast clone(r.results); case Pointer_Type: r.elem = clone(r.elem); + case Multi_Pointer_Type: + r.elem = clone(r.elem); case Array_Type: r.len = clone(r.len); r.elem = clone(r.elem); diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index c64d4d29c..c6922fb35 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -349,6 +349,8 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.results); case Pointer_Type: walk(v, n.elem); + case Multi_Pointer_Type: + walk(v, n.elem); case Array_Type: if n.tag != nil { walk(v, n.tag); diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index cffc114f7..f69d5d00d 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -166,6 +166,7 @@ Type_Kind :: enum u32le { SOA_Struct_Dynamic = 19, Relative_Pointer = 20, Relative_Slice = 21, + Multi_Pointer = 22, } Type_Elems_Cap :: 4; @@ -222,6 +223,7 @@ Type :: struct { // .Simd_Vector - 1 type: 0=element // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer // .Relative_Slice - 2 types: 0=slice type, 1=base integer + // .Multi_Pointer - 1 type: 0=element types: Array(Type_Index), // Used by: diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 6bcb564fe..5dda2fc27 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2440,18 +2440,26 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tok := expect_token(p, .Pointer); elem := parse_type(p); ptr := ast.new(ast.Pointer_Type, tok.pos, elem.end); + ptr.pointer = tok.pos; ptr.elem = elem; return ptr; + case .Open_Bracket: open := expect_token(p, .Open_Bracket); count: ^ast.Expr; - if p.curr_tok.kind == .Question { - tok := expect_token(p, .Question); - q := ast.new(ast.Unary_Expr, tok.pos, end_pos(tok)); - q.op = tok; - count = q; - } else if p.curr_tok.kind == .Dynamic { + switch p.curr_tok.kind { + case .Pointer: + tok := expect_token(p, .Pointer); + close := expect_token(p, .Close_Bracket); + elem := parse_type(p); + t := ast.new(ast.Multi_Pointer_Type, open.pos, elem.end_pos); + t.open = open.pos; + t.pointer = tok.pos; + t.close = close.pos; + t.elem = elem; + return t; + case .Dynamic: tok := expect_token(p, .Dynamic); close := expect_token(p, .Close_Bracket); elem := parse_type(p); @@ -2460,12 +2468,18 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { da.dynamic_pos = tok.pos; da.close = close.pos; da.elem = elem; - return da; - } else if p.curr_tok.kind != .Close_Bracket { + case .Question: + tok := expect_token(p, .Question); + q := ast.new(ast.Unary_Expr, tok.pos, end_pos(tok)); + q.op = tok; + count = q; + case: p.expr_level += 1; count = parse_expr(p, false); p.expr_level -= 1; + case .Close_Bracket: + // handle below } close := expect_token(p, .Close_Bracket); elem := parse_type(p); diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 54cd2aea6..a7aec0d19 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -18,6 +18,7 @@ Type_Info_Boolean :: runtime.Type_Info_Boolean; Type_Info_Any :: runtime.Type_Info_Any; Type_Info_Type_Id :: runtime.Type_Info_Type_Id; Type_Info_Pointer :: runtime.Type_Info_Pointer; +Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer; Type_Info_Procedure :: runtime.Type_Info_Procedure; Type_Info_Array :: runtime.Type_Info_Array; Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array; @@ -50,6 +51,7 @@ Type_Kind :: enum { Any, Type_Id, Pointer, + Multi_Pointer, Procedure, Array, Enumerated_Array, @@ -82,6 +84,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case Type_Info_Any: return .Any; case Type_Info_Type_Id: return .Type_Id; case Type_Info_Pointer: return .Pointer; + case Type_Info_Multi_Pointer: return .Multi_Pointer; case Type_Info_Procedure: return .Procedure; case Type_Info_Array: return .Array; case Type_Info_Enumerated_Array: return .Enumerated_Array; @@ -172,6 +175,7 @@ typeid_elem :: proc(id: typeid) -> typeid { case 256: return f64; } case Type_Info_Pointer: return v.elem.id; + case Type_Info_Multi_Pointer: return v.elem.id; case Type_Info_Array: return v.elem.id; case Type_Info_Enumerated_Array: return v.elem.id; case Type_Info_Slice: return v.elem.id; @@ -298,6 +302,13 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any { } return index({ptr, a.elem.id}, i, loc); + case Type_Info_Multi_Pointer: + ptr := (^rawptr)(val.data)^; + if ptr == nil { + return nil; + } + return index({ptr, a.elem.id}, i, loc); + case Type_Info_Array: runtime.bounds_check_error_loc(loc, i, a.count); offset := uintptr(a.elem.size * i); diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 8c7dc1735..74b0e23b9 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -21,13 +21,11 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { switch x in a.variant { case Type_Info_Named: - y, ok := b.variant.(Type_Info_Named); - if !ok { return false; } + y := b.variant.(Type_Info_Named) or_return; return x.base == y.base; case Type_Info_Integer: - y, ok := b.variant.(Type_Info_Integer); - if !ok { return false; } + y := b.variant.(Type_Info_Integer) or_return; return x.signed == y.signed && x.endianness == y.endianness; case Type_Info_Rune: @@ -63,13 +61,15 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { return ok; case Type_Info_Pointer: - y, ok := b.variant.(Type_Info_Pointer); - if !ok { return false; } + y := b.variant.(Type_Info_Pointer) or_return; + return are_types_identical(x.elem, y.elem); + + case Type_Info_Multi_Pointer: + y := b.variant.(Type_Info_Multi_Pointer) or_return; return are_types_identical(x.elem, y.elem); case Type_Info_Procedure: - y, ok := b.variant.(Type_Info_Procedure); - if !ok { return false; } + y := b.variant.(Type_Info_Procedure) or_return; switch { case x.variadic != y.variadic, x.convention != y.convention: @@ -79,31 +79,26 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results); case Type_Info_Array: - y, ok := b.variant.(Type_Info_Array); - if !ok { return false; } + y := b.variant.(Type_Info_Array) or_return; if x.count != y.count { return false; } return are_types_identical(x.elem, y.elem); case Type_Info_Enumerated_Array: - y, ok := b.variant.(Type_Info_Enumerated_Array); - if !ok { return false; } + y := b.variant.(Type_Info_Enumerated_Array) or_return; if x.count != y.count { return false; } return are_types_identical(x.index, y.index) && are_types_identical(x.elem, y.elem); case Type_Info_Dynamic_Array: - y, ok := b.variant.(Type_Info_Dynamic_Array); - if !ok { return false; } + y := b.variant.(Type_Info_Dynamic_Array) or_return; return are_types_identical(x.elem, y.elem); case Type_Info_Slice: - y, ok := b.variant.(Type_Info_Slice); - if !ok { return false; } + y := b.variant.(Type_Info_Slice) or_return; return are_types_identical(x.elem, y.elem); case Type_Info_Tuple: - y, ok := b.variant.(Type_Info_Tuple); - if !ok { return false; } + y := b.variant.(Type_Info_Tuple) or_return; if len(x.types) != len(y.types) { return false; } for _, i in x.types { xt, yt := x.types[i], y.types[i]; @@ -114,8 +109,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { return true; case Type_Info_Struct: - y, ok := b.variant.(Type_Info_Struct); - if !ok { return false; } + y := b.variant.(Type_Info_Struct) or_return; switch { case len(x.types) != len(y.types), x.is_packed != y.is_packed, @@ -138,8 +132,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { return true; case Type_Info_Union: - y, ok := b.variant.(Type_Info_Union); - if !ok { return false; } + y := b.variant.(Type_Info_Union) or_return; if len(x.variants) != len(y.variants) { return false; } for _, i in x.variants { @@ -153,28 +146,23 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { return false; case Type_Info_Map: - y, ok := b.variant.(Type_Info_Map); - if !ok { return false; } + y := b.variant.(Type_Info_Map) or_return; return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value); case Type_Info_Bit_Set: - y, ok := b.variant.(Type_Info_Bit_Set); - if !ok { return false; } + y := b.variant.(Type_Info_Bit_Set) or_return; return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper; case Type_Info_Simd_Vector: - y, ok := b.variant.(Type_Info_Simd_Vector); - if !ok { return false; } + y := b.variant.(Type_Info_Simd_Vector) or_return; return x.count == y.count && x.elem == y.elem; case Type_Info_Relative_Pointer: - y, ok := b.variant.(Type_Info_Relative_Pointer); - if !ok { return false; } + y := b.variant.(Type_Info_Relative_Pointer) or_return; return x.base_integer == y.base_integer && x.pointer == y.pointer; case Type_Info_Relative_Slice: - y, ok := b.variant.(Type_Info_Relative_Slice); - if !ok { return false; } + y := b.variant.(Type_Info_Relative_Slice) or_return; return x.base_integer == y.base_integer && x.slice == y.slice; } @@ -257,6 +245,11 @@ is_pointer :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Pointer); return ok; } +is_multi_pointer :: proc(info: ^Type_Info) -> bool { + if info == nil { return false; } + _, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer); + return ok; +} is_procedure :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } _, ok := type_info_base(info).variant.(Type_Info_Procedure); @@ -424,6 +417,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info) -> (n: int) { write_string(w, "^"); write_type(w, info.elem); } + case Type_Info_Multi_Pointer: + write_string(w, "[^]"); + write_type(w, info.elem); case Type_Info_Procedure: n += write_string(w, "proc"); if info.params == nil { diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 73af39864..e4c3dd30a 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -74,6 +74,9 @@ Type_Info_Type_Id :: struct {}; Type_Info_Pointer :: struct { elem: ^Type_Info, // nil -> rawptr }; +Type_Info_Multi_Pointer :: struct { + elem: ^Type_Info, +}; Type_Info_Procedure :: struct { params: ^Type_Info, // Type_Info_Tuple results: ^Type_Info, // Type_Info_Tuple @@ -184,6 +187,7 @@ Type_Info :: struct { Type_Info_Any, Type_Info_Type_Id, Type_Info_Pointer, + Type_Info_Multi_Pointer, Type_Info_Procedure, Type_Info_Array, Type_Info_Enumerated_Array, @@ -214,6 +218,7 @@ Typeid_Kind :: enum u8 { Any, Type_Id, Pointer, + Multi_Pointer, Procedure, Array, Enumerated_Array, @@ -340,7 +345,7 @@ Context :: struct { Raw_String :: struct { - data: ^byte, + data: [^]byte, len: int, } diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index 3e4632215..fb8ccab64 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -45,6 +45,24 @@ slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, h bounds_trap(); } +multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! { + print_caller_location(Source_Code_Location{file, line, column, ""}); + print_string(" Invalid slice indices: "); + print_i64(i64(lo)); + print_string(":"); + print_i64(i64(hi)); + print_byte('\n'); + bounds_trap(); +} + + +multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) { + if lo <= hi { + return; + } + multi_pointer_slice_handle_error(file, line, column, lo, hi); +} + slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) { if 0 <= hi && hi <= len { return; diff --git a/core/runtime/print.odin b/core/runtime/print.odin index fd756410a..5a3abcf2f 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -203,6 +203,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) { print_string("^"); print_type(info.elem); } + case Type_Info_Multi_Pointer: + print_string("[^]"); + print_type(info.elem); case Type_Info_Procedure: print_string("proc"); if info.params == nil { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7c46ef4ca..176685804 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 (dst->kind == Type_Pointer && src->kind == Type_MultiPointer) { + if (are_types_identical(dst->Pointer.elem, src->MultiPointer.elem)) { + return 4; + } + } + // [^]T <- ^T + if (dst->kind == Type_MultiPointer && src->kind == Type_Pointer) { + if (are_types_identical(dst->MultiPointer.elem, src->Pointer.elem)) { + return 4; + } } #endif @@ -930,6 +945,16 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type); } return false; + + case Type_MultiPointer: + if (source->kind == Type_MultiPointer) { + isize level = check_is_assignable_to_using_subtype(source->MultiPointer.elem, poly->MultiPointer.elem); + if (level > 0) { + return true; + } + return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->MultiPointer.elem, true, modify_type); + } + return false; case Type_Array: if (source->kind == Type_Array) { if (poly->Array.generic_count != nullptr) { @@ -2392,6 +2417,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 +2434,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 +2457,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 +2470,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 +3372,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 +3411,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 +6146,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 +8184,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 +8253,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 +8314,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 +8343,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) { @@ -8424,6 +8486,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Ast_PolyType: case Ast_ProcType: case Ast_PointerType: + case Ast_MultiPointerType: case Ast_ArrayType: case Ast_DynamicArrayType: case Ast_StructType: @@ -8869,6 +8932,11 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { str = write_expr_to_string(str, pt->type, shorthand); case_end; + case_ast_node(pt, MultiPointerType, node); + str = gb_string_appendc(str, "[^]"); + str = write_expr_to_string(str, pt->type, shorthand); + case_end; + case_ast_node(at, ArrayType, node); str = gb_string_append_rune(str, '['); if (at->count != nullptr && 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/docs_format.cpp b/src/docs_format.cpp index c4fd0359a..ee9842534 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -81,6 +81,7 @@ enum OdinDocTypeKind : u32 { OdinDocType_SOAStructDynamic = 19, OdinDocType_RelativePointer = 20, OdinDocType_RelativeSlice = 21, + OdinDocType_MultiPointer = 22, }; enum OdinDocTypeFlag_Basic : u32 { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 8708724e8..451c44c4e 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -530,6 +530,10 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.kind = OdinDocType_Pointer; doc_type.types = odin_doc_type_as_slice(w, type->Pointer.elem); break; + case Type_MultiPointer: + doc_type.kind = OdinDocType_MultiPointer; + doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem); + break; case Type_Array: doc_type.kind = OdinDocType_Array; doc_type.elem_count_len = 1; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c598fbf62..d0164556a 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; + } + @@ -1708,6 +1727,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri if (is_type_integer(a) || is_type_boolean(a) || is_type_pointer(a) || + is_type_multi_pointer(a) || is_type_proc(a) || is_type_enum(a)) { LLVMIntPredicate pred = {}; @@ -2838,6 +2858,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 +2987,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<lbValue>(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 e9efd989a..2c29f651a 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<Entity *> 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<Entity *> variables; /* Entity_Variable */ \ Array<i64> 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); |