mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 20:00:09 +00:00
Fix index assignment rules for indirection
This commit is contained in:
+11
-4
@@ -1,13 +1,19 @@
|
|||||||
#import "fmt.odin";
|
#import "fmt.odin";
|
||||||
|
|
||||||
main :: proc() {
|
x := [...]int{1, 2, 3, 4};
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
{
|
{
|
||||||
Vec2 :: [vector 2]f32;
|
|
||||||
i: f32 = 1;
|
|
||||||
b := Vec2{i, i};
|
foo :: proc() -> [...]int {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// foo()[0] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/*
|
/*
|
||||||
Version 0.1.0
|
Version 0.1.0
|
||||||
|
|
||||||
@@ -130,5 +136,6 @@ main :: proc() {
|
|||||||
compile_assert(size_of([vector 7]i32) == size_of([7]i32));
|
compile_assert(size_of([vector 7]i32) == size_of([7]i32));
|
||||||
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
|
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-9
@@ -3839,9 +3839,9 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands,
|
|||||||
ok.type = t_bool;
|
ok.type = t_bool;
|
||||||
array_add(operands, val);
|
array_add(operands, val);
|
||||||
array_add(operands, ok);
|
array_add(operands, ok);
|
||||||
continue;
|
} else {
|
||||||
|
array_add(operands, o);
|
||||||
}
|
}
|
||||||
array_add(operands, o);
|
|
||||||
} else {
|
} else {
|
||||||
TypeTuple *tuple = &o.type->Tuple;
|
TypeTuple *tuple = &o.type->Tuple;
|
||||||
for (isize j = 0; j < tuple->variable_count; j++) {
|
for (isize j = 0; j < tuple->variable_count; j++) {
|
||||||
@@ -4097,8 +4097,8 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
|
bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) {
|
||||||
t = base_type(type_deref(t));
|
Type *t = base_type(type_deref(type));
|
||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
@@ -4116,15 +4116,20 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
|
|||||||
|
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
*max_count = t->Array.count;
|
*max_count = t->Array.count;
|
||||||
if (o->mode != Addressing_Variable) {
|
if (indirection) {
|
||||||
|
o->mode = Addressing_Variable;
|
||||||
|
} else if (o->mode != Addressing_Variable) {
|
||||||
o->mode = Addressing_Value;
|
o->mode = Addressing_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
o->type = t->Array.elem;
|
o->type = t->Array.elem;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Type_Vector:
|
case Type_Vector:
|
||||||
*max_count = t->Vector.count;
|
*max_count = t->Vector.count;
|
||||||
if (o->mode != Addressing_Variable) {
|
if (indirection) {
|
||||||
|
o->mode = Addressing_Variable;
|
||||||
|
} else if (o->mode != Addressing_Variable) {
|
||||||
o->mode = Addressing_Value;
|
o->mode = Addressing_Value;
|
||||||
}
|
}
|
||||||
o->type = t->Vector.elem;
|
o->type = t->Vector.elem;
|
||||||
@@ -4138,7 +4143,11 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
|
|||||||
|
|
||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
o->type = t->DynamicArray.elem;
|
o->type = t->DynamicArray.elem;
|
||||||
o->mode = Addressing_Variable;
|
if (indirection) {
|
||||||
|
o->mode = Addressing_Variable;
|
||||||
|
} else if (o->mode != Addressing_Variable) {
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5023,6 +5032,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type *t = base_type(type_deref(o->type));
|
Type *t = base_type(type_deref(o->type));
|
||||||
|
bool is_ptr = is_type_pointer(o->type);
|
||||||
bool is_const = o->mode == Addressing_Constant;
|
bool is_const = o->mode == Addressing_Constant;
|
||||||
|
|
||||||
if (is_type_map(t)) {
|
if (is_type_map(t)) {
|
||||||
@@ -5039,7 +5049,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
}
|
}
|
||||||
|
|
||||||
i64 max_count = -1;
|
i64 max_count = -1;
|
||||||
bool valid = check_set_index_data(o, t, &max_count);
|
bool valid = check_set_index_data(o, t, is_ptr, &max_count);
|
||||||
|
|
||||||
if (is_const) {
|
if (is_const) {
|
||||||
valid = false;
|
valid = false;
|
||||||
@@ -5048,7 +5058,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
|
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
|
||||||
Entity *found = find_using_index_expr(t);
|
Entity *found = find_using_index_expr(t);
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
valid = check_set_index_data(o, found->type, &max_count);
|
valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-33
@@ -182,40 +182,40 @@ bool check_is_terminating(AstNode *node) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||||
if (op_a->mode == Addressing_Invalid ||
|
if (rhs->mode == Addressing_Invalid ||
|
||||||
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) {
|
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *node = unparen_expr(lhs);
|
AstNode *node = unparen_expr(lhs_node);
|
||||||
|
|
||||||
// NOTE(bill): Ignore assignments to `_`
|
// NOTE(bill): Ignore assignments to `_`
|
||||||
if (node->kind == AstNode_Ident &&
|
if (node->kind == AstNode_Ident &&
|
||||||
str_eq(node->Ident.string, str_lit("_"))) {
|
str_eq(node->Ident.string, str_lit("_"))) {
|
||||||
add_entity_definition(&c->info, node, NULL);
|
add_entity_definition(&c->info, node, NULL);
|
||||||
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
|
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
|
||||||
if (op_a->mode == Addressing_Invalid) {
|
if (rhs->mode == Addressing_Invalid) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return op_a->type;
|
return rhs->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *e = NULL;
|
Entity *e = NULL;
|
||||||
bool used = false;
|
bool used = false;
|
||||||
Operand op_b = {Addressing_Invalid};
|
Operand lhs = {Addressing_Invalid};
|
||||||
|
|
||||||
|
|
||||||
check_expr(c, &op_b, lhs);
|
check_expr(c, &lhs, lhs_node);
|
||||||
if (op_b.mode == Addressing_Invalid ||
|
if (lhs.mode == Addressing_Invalid ||
|
||||||
op_b.type == t_invalid) {
|
lhs.type == t_invalid) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (op_a->mode == Addressing_Overload) {
|
if (rhs->mode == Addressing_Overload) {
|
||||||
isize overload_count = op_a->overload_count;
|
isize overload_count = rhs->overload_count;
|
||||||
Entity **procs = op_a->overload_entities;
|
Entity **procs = rhs->overload_entities;
|
||||||
GB_ASSERT(procs != NULL && overload_count > 0);
|
GB_ASSERT(procs != NULL && overload_count > 0);
|
||||||
|
|
||||||
// NOTE(bill): These should be done
|
// NOTE(bill): These should be done
|
||||||
@@ -227,19 +227,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
|||||||
Operand x = {0};
|
Operand x = {0};
|
||||||
x.mode = Addressing_Value;
|
x.mode = Addressing_Value;
|
||||||
x.type = t;
|
x.type = t;
|
||||||
if (check_is_assignable_to(c, &x, op_b.type)) {
|
if (check_is_assignable_to(c, &x, lhs.type)) {
|
||||||
e = procs[i];
|
e = procs[i];
|
||||||
add_entity_use(c, op_a->expr, e);
|
add_entity_use(c, rhs->expr, e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e != NULL) {
|
if (e != NULL) {
|
||||||
// HACK TODO(bill): Should the entities be freed as it's technically a leak
|
// HACK TODO(bill): Should the entities be freed as it's technically a leak
|
||||||
op_a->mode = Addressing_Value;
|
rhs->mode = Addressing_Value;
|
||||||
op_a->type = e->type;
|
rhs->type = e->type;
|
||||||
op_a->overload_count = 0;
|
rhs->overload_count = 0;
|
||||||
op_a->overload_entities = NULL;
|
rhs->overload_entities = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (node->kind == AstNode_Ident) {
|
if (node->kind == AstNode_Ident) {
|
||||||
@@ -256,43 +256,62 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
|||||||
e->flags |= EntityFlag_Used;
|
e->flags |= EntityFlag_Used;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *assignment_type = op_b.type;
|
Type *assignment_type = lhs.type;
|
||||||
switch (op_b.mode) {
|
switch (lhs.mode) {
|
||||||
case Addressing_Invalid:
|
case Addressing_Invalid:
|
||||||
return NULL;
|
return NULL;
|
||||||
case Addressing_Variable:
|
case Addressing_Variable:
|
||||||
case Addressing_MapIndex:
|
|
||||||
break;
|
break;
|
||||||
|
case Addressing_MapIndex: {
|
||||||
|
AstNode *ln = unparen_expr(lhs_node);
|
||||||
|
if (ln->kind == AstNode_IndexExpr) {
|
||||||
|
AstNode *x = ln->IndexExpr.expr;
|
||||||
|
TypeAndValue *tav = type_and_value_of_expression(&c->info, x);
|
||||||
|
GB_ASSERT(tav != NULL);
|
||||||
|
switch (tav->mode) {
|
||||||
|
case Addressing_Variable:
|
||||||
|
break;
|
||||||
|
case Addressing_Value:
|
||||||
|
if (!is_type_pointer(tav->type)) {
|
||||||
|
gbString str = expr_to_string(lhs.expr);
|
||||||
|
error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default: {
|
default: {
|
||||||
if (op_b.expr->kind == AstNode_SelectorExpr) {
|
if (lhs.expr->kind == AstNode_SelectorExpr) {
|
||||||
// NOTE(bill): Extra error checks
|
// NOTE(bill): Extra error checks
|
||||||
Operand op_c = {Addressing_Invalid};
|
Operand op_c = {Addressing_Invalid};
|
||||||
ast_node(se, SelectorExpr, op_b.expr);
|
ast_node(se, SelectorExpr, lhs.expr);
|
||||||
check_expr(c, &op_c, se->expr);
|
check_expr(c, &op_c, se->expr);
|
||||||
if (op_c.mode == Addressing_MapIndex) {
|
if (op_c.mode == Addressing_MapIndex) {
|
||||||
gbString str = expr_to_string(op_b.expr);
|
gbString str = expr_to_string(lhs.expr);
|
||||||
error_node(op_b.expr, "Cannot assign to record field `%s` in map", str);
|
error_node(lhs.expr, "Cannot assign to record field `%s` in map", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gbString str = expr_to_string(op_b.expr);
|
gbString str = expr_to_string(lhs.expr);
|
||||||
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
|
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
|
||||||
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str);
|
error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
|
||||||
} else {
|
} else {
|
||||||
error_node(op_b.expr, "Cannot assign to `%s`", str);
|
error_node(lhs.expr, "Cannot assign to `%s`", str);
|
||||||
}
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_assignment(c, op_a, assignment_type, str_lit("assignment"));
|
check_assignment(c, rhs, assignment_type, str_lit("assignment"));
|
||||||
if (op_a->mode == Addressing_Invalid) {
|
if (rhs->mode == Addressing_Invalid) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return op_a->type;
|
return rhs->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
|
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
|
||||||
|
|||||||
Reference in New Issue
Block a user