Commit e8550814c5
Changed files (4)
example/arrays/arrays.zig
@@ -9,9 +9,7 @@ extern {
export fn _start() -> unreachable {
let mut array : [i32; 10];
- exit(array[1]);
-
- //array[4] = array[1] + 5;
-
+ array[4] = array[1] + 5;
+ exit(0);
}
src/analyze.cpp
@@ -10,6 +10,9 @@
#include "zig_llvm.hpp"
#include "os.hpp"
+static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ TypeTableEntry *expected_type, AstNode *node);
+
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
case NodeTypeFnCallExpr:
@@ -476,6 +479,35 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
}
}
+static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ AstNode *node)
+{
+ TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
+ node->data.array_access_expr.array_ref_expr);
+
+ TypeTableEntry *return_type;
+
+ if (array_type->id == TypeTableEntryIdArray) {
+ return_type = array_type->data.array.child_type;
+ } else {
+ if (array_type->id != TypeTableEntryIdInvalid) {
+ add_node_error(g, node, buf_sprintf("array access of non-array"));
+ }
+ return_type = g->builtin_types.entry_invalid;
+ }
+
+ TypeTableEntry *subscript_type = analyze_expression(g, import, context, nullptr,
+ node->data.array_access_expr.subscript);
+ if (subscript_type->id != TypeTableEntryIdInt &&
+ subscript_type->id != TypeTableEntryIdInvalid)
+ {
+ add_node_error(g, node,
+ buf_sprintf("array subscripts must be integers"));
+ }
+
+ return return_type;
+}
+
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
@@ -593,6 +625,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case BinOpTypeAssign:
{
AstNode *lhs_node = node->data.bin_op_expr.op1;
+ TypeTableEntry *expected_rhs_type = nullptr;
if (lhs_node->type == NodeTypeSymbol) {
Buf *name = &lhs_node->data.symbol;
LocalVariableTableEntry *var = find_local_variable(context, name);
@@ -601,18 +634,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
add_node_error(g, lhs_node,
buf_sprintf("cannot assign to constant variable"));
} else {
- analyze_expression(g, import, context, var->type,
- node->data.bin_op_expr.op2);
+ expected_rhs_type = var->type;
}
} else {
add_node_error(g, lhs_node,
buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
}
-
+ } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
+ expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
} else {
add_node_error(g, lhs_node,
buf_sprintf("expected a bare identifier"));
}
+ analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
return_type = g->builtin_types.entry_void;
break;
}
@@ -736,25 +770,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
}
case NodeTypeArrayAccessExpr:
- {
- // here we are always reading the array
- TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
- node->data.array_access_expr.array_ref_expr);
- if (array_type->id == TypeTableEntryIdArray) {
- TypeTableEntry *subscript_type = analyze_expression(g, import, context,
- nullptr, node->data.array_access_expr.subscript);
- if (subscript_type->id != TypeTableEntryIdInt) {
- add_node_error(g, node,
- buf_sprintf("array subscripts must be integers"));
- }
- return_type = array_type->data.array.child_type;
- } else {
- add_node_error(g, node, buf_sprintf("array access of non-array"));
- return_type = g->builtin_types.entry_invalid;
- }
-
- break;
- }
+ // for reading array access; assignment handled elsewhere
+ return_type = analyze_array_access_expr(g, import, context, node);
+ break;
case NodeTypeNumberLiteral:
// TODO: generic literal int type
return_type = g->builtin_types.entry_i32;
src/codegen.cpp
@@ -167,7 +167,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
}
}
-static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
+static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeArrayAccessExpr);
LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);
@@ -180,8 +180,14 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
LLVMConstInt(LLVMInt32Type(), 0, false),
subscript_value
};
- LLVMValueRef result_ptr = LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
- return LLVMBuildLoad(g->builder, result_ptr, "");
+ return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
+}
+
+static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeArrayAccessExpr);
+
+ LLVMValueRef ptr = gen_array_ptr(g, node);
+ return LLVMBuildLoad(g->builder, ptr, "");
}
static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
@@ -437,22 +443,32 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
return phi;
}
+
static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
- AstNode *symbol_node = node->data.bin_op_expr.op1;
- assert(symbol_node->type == NodeTypeSymbol);
+ AstNode *lhs_node = node->data.bin_op_expr.op1;
- LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
- &symbol_node->data.symbol);
+ if (lhs_node->type == NodeTypeSymbol) {
+ LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
+ &lhs_node->data.symbol);
- // semantic checking ensures no variables are constant
- assert(!var->is_const);
+ // semantic checking ensures no variables are constant
+ assert(!var->is_const);
- LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
+ LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
+
+ add_debug_source_node(g, node);
+ return LLVMBuildStore(g->builder, value, var->value_ref);
+ } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
+ LLVMValueRef ptr = gen_array_ptr(g, lhs_node);
+ LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
+ add_debug_source_node(g, node);
+ return LLVMBuildStore(g->builder, value, ptr);
+ } else {
+ zig_panic("bad assign target");
+ }
- add_debug_source_node(g, node);
- return LLVMBuildStore(g->builder, value, var->value_ref);
}
static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
test/run_tests.cpp
@@ -520,6 +520,21 @@ fn f() {
(let a = 0);
}
)SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'let'");
+
+ add_compile_fail_case("array access errors", R"SOURCE(
+fn f() {
+ let mut bad : bool;
+ i[i] = i[i];
+ bad[bad] = bad[bad];
+}
+ )SOURCE", 8, ".tmp_source.zig:4:5: error: use of undeclared identifier 'i'",
+ ".tmp_source.zig:4:7: error: use of undeclared identifier 'i'",
+ ".tmp_source.zig:4:12: error: use of undeclared identifier 'i'",
+ ".tmp_source.zig:4:14: error: use of undeclared identifier 'i'",
+ ".tmp_source.zig:5:8: error: array access of non-array",
+ ".tmp_source.zig:5:8: error: array subscripts must be integers",
+ ".tmp_source.zig:5:19: error: array access of non-array",
+ ".tmp_source.zig:5:19: error: array subscripts must be integers");
}
static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) {