aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp82
1 files changed, 67 insertions, 15 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) {