浏览代码

Fix index assignment rules for indirection

Ginger Bill 8 年之前
父节点
当前提交
763cd2649d
共有 3 个文件被更改,包括 82 次插入46 次删除
  1. 11 4
      code/demo.odin
  2. 19 9
      src/check_expr.c
  3. 52 33
      src/check_stmt.c

+ 11 - 4
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
 	}
+*/
 }
 

+ 19 - 9
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);
 			}
 		}
 

+ 52 - 33
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) {