diff --git a/code/demo.odin b/code/demo.odin index 238d638e4..c9cf55616 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,13 +1,19 @@ #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 @@ -130,5 +136,6 @@ main :: proc() { 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 } +*/ } diff --git a/src/check_expr.c b/src/check_expr.c index 3b58dc904..5b91ffd39 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -3839,9 +3839,9 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, ok.type = t_bool; array_add(operands, val); array_add(operands, ok); - continue; + } else { + array_add(operands, o); } - array_add(operands, o); } else { TypeTuple *tuple = &o.type->Tuple; 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) { - t = base_type(type_deref(t)); +bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) { + Type *t = base_type(type_deref(type)); switch (t->kind) { case Type_Basic: @@ -4116,15 +4116,20 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { case Type_Array: *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->type = t->Array.elem; return true; case Type_Vector: *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->type = t->Vector.elem; @@ -4138,7 +4143,11 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { case Type_DynamicArray: 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; } @@ -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)); + bool is_ptr = is_type_pointer(o->type); bool is_const = o->mode == Addressing_Constant; 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; - 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) { 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))) { Entity *found = find_using_index_expr(t); 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); } } diff --git a/src/check_stmt.c b/src/check_stmt.c index bbe254615..983c9f25f 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -182,40 +182,40 @@ bool check_is_terminating(AstNode *node) { return false; } -Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { - if (op_a->mode == Addressing_Invalid || - (op_a->type == t_invalid && op_a->mode != Addressing_Overload)) { +Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { + if (rhs->mode == Addressing_Invalid || + (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) { return NULL; } - AstNode *node = unparen_expr(lhs); + AstNode *node = unparen_expr(lhs_node); // NOTE(bill): Ignore assignments to `_` if (node->kind == AstNode_Ident && str_eq(node->Ident.string, str_lit("_"))) { add_entity_definition(&c->info, node, NULL); - check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier")); - if (op_a->mode == Addressing_Invalid) { + check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier")); + if (rhs->mode == Addressing_Invalid) { return NULL; } - return op_a->type; + return rhs->type; } Entity *e = NULL; bool used = false; - Operand op_b = {Addressing_Invalid}; + Operand lhs = {Addressing_Invalid}; - check_expr(c, &op_b, lhs); - if (op_b.mode == Addressing_Invalid || - op_b.type == t_invalid) { + check_expr(c, &lhs, lhs_node); + if (lhs.mode == Addressing_Invalid || + lhs.type == t_invalid) { return NULL; } - if (op_a->mode == Addressing_Overload) { - isize overload_count = op_a->overload_count; - Entity **procs = op_a->overload_entities; + if (rhs->mode == Addressing_Overload) { + isize overload_count = rhs->overload_count; + Entity **procs = rhs->overload_entities; GB_ASSERT(procs != NULL && overload_count > 0); // NOTE(bill): These should be done @@ -227,19 +227,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { Operand x = {0}; x.mode = Addressing_Value; 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]; - add_entity_use(c, op_a->expr, e); + add_entity_use(c, rhs->expr, e); break; } } if (e != NULL) { // HACK TODO(bill): Should the entities be freed as it's technically a leak - op_a->mode = Addressing_Value; - op_a->type = e->type; - op_a->overload_count = 0; - op_a->overload_entities = NULL; + rhs->mode = Addressing_Value; + rhs->type = e->type; + rhs->overload_count = 0; + rhs->overload_entities = NULL; } } else { if (node->kind == AstNode_Ident) { @@ -256,43 +256,62 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { e->flags |= EntityFlag_Used; } - Type *assignment_type = op_b.type; - switch (op_b.mode) { + Type *assignment_type = lhs.type; + switch (lhs.mode) { case Addressing_Invalid: return NULL; case Addressing_Variable: - case Addressing_MapIndex: 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: { - if (op_b.expr->kind == AstNode_SelectorExpr) { + if (lhs.expr->kind == AstNode_SelectorExpr) { // NOTE(bill): Extra error checks 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); if (op_c.mode == Addressing_MapIndex) { - gbString str = expr_to_string(op_b.expr); - error_node(op_b.expr, "Cannot assign to record field `%s` in map", str); + gbString str = expr_to_string(lhs.expr); + error_node(lhs.expr, "Cannot assign to record field `%s` in map", str); gb_string_free(str); 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) { - error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str); + error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str); } else { - error_node(op_b.expr, "Cannot assign to `%s`", str); + error_node(lhs.expr, "Cannot assign to `%s`", str); } gb_string_free(str); } break; } - check_assignment(c, op_a, assignment_type, str_lit("assignment")); - if (op_a->mode == Addressing_Invalid) { + check_assignment(c, rhs, assignment_type, str_lit("assignment")); + if (rhs->mode == Addressing_Invalid) { return NULL; } - return op_a->type; + return rhs->type; } bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {