aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2021-08-22 11:50:47 +0100
committerGitHub <noreply@github.com>2021-08-22 11:50:47 +0100
commitd3fee9d76172172a0f8a70b96938dff45f3dd7e6 (patch)
treee3ccf349254e041a97cb8e5c5860f2b39eb3e46d
parent93b5befe45b6464f30f7a9404d1db2d84edf201f (diff)
parent36a6805b7cdb8b5e4014b03756f969ce6548ff73 (diff)
Merge pull request #1093 from odin-lang/multi-pointers
Multi Pointers `[^]T`
-rw-r--r--core/encoding/json/marshal.odin3
-rw-r--r--core/fmt/fmt.odin42
-rw-r--r--core/odin/ast/ast.odin8
-rw-r--r--core/odin/ast/clone.odin2
-rw-r--r--core/odin/ast/walk.odin2
-rw-r--r--core/odin/doc-format/doc_format.odin2
-rw-r--r--core/odin/parser/parser.odin30
-rw-r--r--core/reflect/reflect.odin11
-rw-r--r--core/reflect/types.odin60
-rw-r--r--core/runtime/core.odin7
-rw-r--r--core/runtime/error_checks.odin18
-rw-r--r--core/runtime/print.odin3
-rw-r--r--src/check_expr.cpp98
-rw-r--r--src/check_type.cpp6
-rw-r--r--src/checker.cpp11
-rw-r--r--src/docs_format.cpp1
-rw-r--r--src/docs_writer.cpp4
-rw-r--r--src/llvm_backend_expr.cpp56
-rw-r--r--src/llvm_backend_general.cpp35
-rw-r--r--src/llvm_backend_type.cpp15
-rw-r--r--src/parser.cpp16
-rw-r--r--src/parser.hpp4
-rw-r--r--src/parser_pos.cpp2
-rw-r--r--src/types.cpp110
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);