Commit d8f6388b63
Changed files (7)
example
cat
example/cat/main.zig
@@ -13,7 +13,7 @@ pub fn main(args: [][]u8) -> %void {
for (arg, args[1...]) {
if (arg == "-") {
catted_anything = true;
- %return cat_stream(stdin);
+ cat_stream(stdin) %% |err| return err;
} else if (arg[0] == '-') {
return usage(exe);
} else {
@@ -24,11 +24,11 @@ pub fn main(args: [][]u8) -> %void {
defer is.close();
catted_anything = true;
- %return cat_stream(is);
+ cat_stream(is) %% |err| return err;
}
}
if (!catted_anything) {
- %return cat_stream(stdin)
+ cat_stream(stdin) %% |err| return err;
}
}
src/all_types.hpp
@@ -1049,6 +1049,19 @@ struct BuiltinFnEntry {
LLVMValueRef fn_val;
};
+enum CIntType {
+ CIntTypeShort,
+ CIntTypeUShort,
+ CIntTypeInt,
+ CIntTypeUInt,
+ CIntTypeLong,
+ CIntTypeULong,
+ CIntTypeLongLong,
+ CIntTypeULongLong,
+
+ CIntTypeCount,
+};
+
struct CodeGen {
LLVMModuleRef module;
ZigList<ErrorMsg*> errors;
@@ -1072,7 +1085,7 @@ struct CodeGen {
struct {
TypeTableEntry *entry_bool;
TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
- TypeTableEntry *entry_c_int[8];
+ TypeTableEntry *entry_c_int[CIntTypeCount];
TypeTableEntry *entry_c_long_double;
TypeTableEntry *entry_u8;
TypeTableEntry *entry_u16;
@@ -1196,16 +1209,6 @@ struct BlockContext {
Buf *c_import_buf;
};
-enum CIntType {
- CIntTypeShort,
- CIntTypeUShort,
- CIntTypeInt,
- CIntTypeUInt,
- CIntTypeLong,
- CIntTypeULong,
- CIntTypeLongLong,
- CIntTypeULongLong,
-};
#endif
src/analyze.cpp
@@ -2159,6 +2159,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
&get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
if (field_val->ok) {
const_val->data.x_struct.fields[field_index] = field_val;
+ const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var;
} else {
const_val->ok = false;
}
@@ -2197,6 +2198,8 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;
if (elem_const_val->ok) {
const_val->data.x_array.fields[i] = elem_const_val;
+ const_val->depends_on_compile_var = const_val->depends_on_compile_var ||
+ elem_const_val->depends_on_compile_var;
} else {
const_val->ok = false;
}
@@ -2431,9 +2434,12 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node,
return g->builtin_types.entry_pure_error;
}
-static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) {
+static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value,
+ bool depends_on_compile_var)
+{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
+ expr->const_val.depends_on_compile_var = depends_on_compile_var;
expr->const_val.data.x_bool = value;
return g->builtin_types.entry_bool;
}
@@ -2817,7 +2823,8 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
zig_unreachable();
}
- return resolve_expr_const_val_as_bool(g, node, answer);
+ bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
+ return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
}
static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -2844,7 +2851,8 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i
}
bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool);
- return resolve_expr_const_val_as_bool(g, node, answer);
+ bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
+ return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
}
static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -3001,6 +3009,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
}
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
const_val->ok = true;
+ const_val->depends_on_compile_var = op1_val->depends_on_compile_var ||
+ op2_val->depends_on_compile_var;
ConstExprValue *all_fields = allocate<ConstExprValue>(2);
ConstExprValue *ptr_field = &all_fields[0];
@@ -3444,51 +3454,111 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor
return g->builtin_types.entry_unreachable;
}
-static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *then_block, AstNode *else_node, AstNode *parent_node)
+static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ TypeTableEntry *expected_type, AstNode *node,
+ AstNode **then_node, AstNode **else_node, bool cond_is_const, bool cond_bool_val)
{
- TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type, then_block);
-
- TypeTableEntry *else_type;
- if (else_node) {
- else_type = analyze_expression(g, import, context, expected_type, else_node);
- } else {
- else_type = resolve_type_compatibility(g, import, context, parent_node, expected_type,
- g->builtin_types.entry_void);
+ if (!*else_node) {
+ *else_node = create_ast_void_node(g, import, node);
+ normalize_parent_ptrs(node);
}
+ TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type, *then_node);
+ TypeTableEntry *else_type = analyze_expression(g, import, context, expected_type, *else_node);
+ if (then_type->id == TypeTableEntryIdInvalid || else_type->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ }
+
+ TypeTableEntry *result_type;
if (expected_type) {
- return (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
+ result_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
} else {
- AstNode *op_nodes[] = {then_block, else_node};
+ AstNode *op_nodes[] = {*then_node, *else_node};
TypeTableEntry *op_types[] = {then_type, else_type};
- return resolve_peer_type_compatibility(g, import, context, parent_node, op_nodes, op_types, 2);
+ result_type = resolve_peer_type_compatibility(g, import, context, node, op_nodes, op_types, 2);
+ }
+
+ if (!cond_is_const) {
+ return result_type;
}
+
+ ConstExprValue *other_const_val;
+ if (cond_bool_val) {
+ other_const_val = &get_resolved_expr(*then_node)->const_val;
+ } else {
+ other_const_val = &get_resolved_expr(*else_node)->const_val;
+ }
+ if (!other_const_val->ok) {
+ return result_type;
+ }
+
+ ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+ *const_val = *other_const_val;
+ return result_type;
}
static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
- analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_bool_expr.condition);
+ AstNode **cond = &node->data.if_bool_expr.condition;
+ TypeTableEntry *cond_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *cond);
+
+ if (cond_type->id == TypeTableEntryIdInvalid) {
+ return cond_type;
+ }
- return analyze_if_then_else(g, import, context, expected_type,
- node->data.if_bool_expr.then_block,
- node->data.if_bool_expr.else_node,
- node);
+ ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
+ if (cond_val->ok && !cond_val->depends_on_compile_var) {
+ const char *str_val = cond_val->data.x_bool ? "true" : "false";
+ add_node_error(g, first_executing_node(*cond),
+ buf_sprintf("condition is always %s; unnecessary if statement", str_val));
+ }
+
+ bool cond_is_const = cond_val->ok;
+ bool cond_bool_val = cond_val->data.x_bool;
+
+ AstNode **then_node = &node->data.if_bool_expr.then_block;
+ AstNode **else_node = &node->data.if_bool_expr.else_node;
+
+ return analyze_if(g, import, context, expected_type, node,
+ then_node, else_node, cond_is_const, cond_bool_val);
}
-static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
TypeTableEntry *expected_type, AstNode *node)
{
assert(node->type == NodeTypeIfVarExpr);
- BlockContext *child_context = new_block_context(node, context);
+ BlockContext *child_context = new_block_context(node, parent_context);
analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);
+ VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
+ if (var->type->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ }
+ AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr;
+ ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val;
+ bool cond_is_const = var_const_val->ok;
+ bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false;
+
+
+ AstNode **then_node = &node->data.if_var_expr.then_block;
+ AstNode **else_node = &node->data.if_var_expr.else_node;
- return analyze_if_then_else(g, import, child_context, expected_type,
- node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);
+ return analyze_if(g, import, child_context, expected_type,
+ node, then_node, else_node, cond_is_const, cond_bool_val);
+}
+
+static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
+ assert(int_type->id == TypeTableEntryIdInt);
+
+ for (int i = 0; i < CIntTypeCount; i += 1) {
+ if (int_type == g->builtin_types.entry_c_int[i]) {
+ return true;
+ }
+ }
+ return false;
}
static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -3504,6 +3574,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
} else if (type_entry->id == TypeTableEntryIdInt) {
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
const_val->ok = true;
+ const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
if (is_max) {
if (type_entry->data.integral.is_signed) {
int64_t val;
@@ -3558,7 +3629,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
zig_panic("TODO analyze_min_max_value float");
return type_entry;
} else if (type_entry->id == TypeTableEntryIdBool) {
- return resolve_expr_const_val_as_bool(g, node, is_max);
+ return resolve_expr_const_val_as_bool(g, node, is_max, false);
} else {
add_node_error(g, node,
buf_sprintf(err_format, buf_ptr(&type_entry->name)));
@@ -3573,6 +3644,8 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
if (!other_val->ok) {
return;
}
+ const_val->depends_on_compile_var = other_val->depends_on_compile_var;
+
assert(other_val != const_val);
switch (node->data.fn_call_expr.cast_op) {
case CastOpNoCast:
@@ -4132,11 +4205,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
const_val->depends_on_compile_var = true;
if (buf_eql_str(&var_name, "is_big_endian")) {
- return resolve_expr_const_val_as_bool(g, node, g->is_big_endian);
+ return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
} else if (buf_eql_str(&var_name, "is_release")) {
- return resolve_expr_const_val_as_bool(g, node, g->is_release_build);
+ return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
} else if (buf_eql_str(&var_name, "is_test")) {
- return resolve_expr_const_val_as_bool(g, node, g->is_test_build);
+ return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
} else {
add_node_error(g, *str_node,
buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));
@@ -4353,7 +4426,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
bool answer = !target_const_val->data.x_bool;
- return resolve_expr_const_val_as_bool(g, node, answer);
+ return resolve_expr_const_val_as_bool(g, node, answer, target_const_val->depends_on_compile_var);
}
case PrefixOpBinNot:
{
@@ -4390,6 +4463,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
const_val->ok = true;
+ const_val->depends_on_compile_var = target_const_val->depends_on_compile_var;
bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum);
return expr_type;
} else {
@@ -4880,7 +4954,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
node->data.char_literal.value);
break;
case NodeTypeBoolLiteral:
- return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value);
+ return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value, false);
break;
case NodeTypeNullLiteral:
return_type = analyze_null_literal_expr(g, import, context, expected_type, node);
src/codegen.cpp
@@ -1737,81 +1737,60 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
zig_unreachable();
}
-static LLVMValueRef gen_defer(CodeGen *g, AstNode *node) {
- assert(node->type == NodeTypeDefer);
-
-
- return nullptr;
-}
-
static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,
AstNode *then_node, AstNode *else_node)
{
- TypeTableEntry *then_type = get_expr_type(then_node);
- bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&
- then_type->id != TypeTableEntryIdVoid);
-
- if (else_node) {
- LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
- LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
-
- LLVMBasicBlockRef endif_block;
- bool then_endif_reachable = get_expr_type(then_node)->id != TypeTableEntryIdUnreachable;
- bool else_endif_reachable = get_expr_type(else_node)->id != TypeTableEntryIdUnreachable;
- if (then_endif_reachable || else_endif_reachable) {
- endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
- }
+ assert(then_node);
+ assert(else_node);
- LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
-
- LLVMPositionBuilderAtEnd(g->builder, then_block);
- LLVMValueRef then_expr_result = gen_expr(g, then_node);
- if (then_endif_reachable) {
- LLVMBuildBr(g->builder, endif_block);
- }
- LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
-
- LLVMPositionBuilderAtEnd(g->builder, else_block);
- LLVMValueRef else_expr_result = gen_expr(g, else_node);
- if (else_endif_reachable) {
- LLVMBuildBr(g->builder, endif_block);
- }
- LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
+ TypeTableEntry *then_type = get_expr_type(then_node);
+ TypeTableEntry *else_type = get_expr_type(else_node);
- if (then_endif_reachable || else_endif_reachable) {
- LLVMPositionBuilderAtEnd(g->builder, endif_block);
- if (use_expr_value) {
- LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
- LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
- LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
- LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+ bool use_then_value = type_has_bits(then_type);
+ bool use_else_value = type_has_bits(else_type);
- return phi;
- }
- }
+ LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
+ LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
- return nullptr;
+ LLVMBasicBlockRef endif_block;
+ bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
+ bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
+ if (then_endif_reachable || else_endif_reachable) {
+ endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
}
- assert(!use_expr_value || then_type->id == TypeTableEntryIdErrorUnion);
-
- LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
- LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
-
- LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
+ LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
LLVMPositionBuilderAtEnd(g->builder, then_block);
- gen_expr(g, then_node);
- if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
+ LLVMValueRef then_expr_result = gen_expr(g, then_node);
+ if (then_endif_reachable) {
LLVMBuildBr(g->builder, endif_block);
+ }
+ LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
- LLVMPositionBuilderAtEnd(g->builder, endif_block);
-
- if (use_expr_value) {
- return LLVMConstNull(g->err_tag_type->type_ref);
- } else {
- return nullptr;
+ LLVMPositionBuilderAtEnd(g->builder, else_block);
+ LLVMValueRef else_expr_result = gen_expr(g, else_node);
+ if (else_endif_reachable) {
+ LLVMBuildBr(g->builder, endif_block);
}
+ LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
+
+ if (then_endif_reachable || else_endif_reachable) {
+ LLVMPositionBuilderAtEnd(g->builder, endif_block);
+ if (use_then_value && use_else_value) {
+ LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
+ LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
+ LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
+ LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
+ return phi;
+ } else if (use_then_value) {
+ return then_expr_result;
+ } else if (use_else_value) {
+ return else_expr_result;
+ }
+ }
+
+ return nullptr;
}
static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
@@ -1866,14 +1845,6 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
return return_value;
}
-//static int block_exit_path_count(BlockContext *block_context) {
-// int sum = 0;
-// for (int i = 0; i < BlockExitPathCount; i += 1) {
-// sum += block_context->block_exit_paths[i] ? 1 : 0;
-// }
-// return sum;
-//}
-
static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
assert(block_node->type == NodeTypeBlock);
@@ -2553,7 +2524,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeReturnExpr:
return gen_return_expr(g, node);
case NodeTypeDefer:
- return gen_defer(g, node);
+ // nothing to do
+ return nullptr;
case NodeTypeVariableDeclaration:
return gen_var_decl_expr(g, node);
case NodeTypePrefixOpExpr:
@@ -3191,6 +3163,7 @@ static const CIntTypeInfo c_int_type_infos[] = {
static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {
// TODO other architectures besides x86_64
+ // other operating systems besides linux
switch (id) {
case CIntTypeShort:
case CIntTypeUShort:
@@ -3203,6 +3176,8 @@ static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {
case CIntTypeLongLong:
case CIntTypeULongLong:
return 64;
+ case CIntTypeCount:
+ zig_unreachable();
}
zig_unreachable();
}
std/test_runner.zig
@@ -16,6 +16,7 @@ pub fn run_tests() -> %void {
%%stderr.print_str(" ");
%%stderr.print_str(test_fn.name);
%%stderr.print_str("...");
+ %%stderr.flush();
test_fn.func();
test/run_tests.cpp
@@ -225,26 +225,6 @@ pub fn foo_function() -> bool {
)SOURCE");
}
- add_simple_case("if statements", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- if (1 != 0) {
- %%stdout.printf("1 is true\n");
- } else {
- %%stdout.printf("1 is false\n");
- }
- if (0 != 0) {
- %%stdout.printf("0 is true\n");
- } else if (1 - 1 != 0) {
- %%stdout.printf("1 - 1 is true\n");
- }
- if (!(0 != 0)) {
- %%stdout.printf("!0 is true\n");
- }
-}
- )SOURCE", "1 is true\n!0 is true\n");
-
add_simple_case("params", R"SOURCE(
import "std.zig";
@@ -259,46 +239,6 @@ pub fn main(args: [][]u8) -> %void {
}
)SOURCE", "pass\n");
- add_simple_case("local variables", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- const a : i32 = 1;
- const b = i32(2);
- if (a + b == 3) {
- %%stdout.printf("OK\n");
- }
-}
- )SOURCE", "OK\n");
-
- add_simple_case("bool literals", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- if (true) { %%stdout.printf("OK 1\n"); }
- if (false) { %%stdout.printf("BAD 1\n"); }
- if (!true) { %%stdout.printf("BAD 2\n"); }
- if (!false) { %%stdout.printf("OK 2\n"); }
-}
- )SOURCE", "OK 1\nOK 2\n");
-
- add_simple_case("separate block scopes", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- if (true) {
- const no_conflict : i32 = 5;
- if (no_conflict == 5) { %%stdout.printf("OK 1\n"); }
- }
-
- const c = {
- const no_conflict = i32(10);
- no_conflict
- };
- if (c == 10) { %%stdout.printf("OK 2\n"); }
-}
- )SOURCE", "OK 1\nOK 2\n");
-
add_simple_case("void parameters", R"SOURCE(
import "std.zig";
@@ -314,48 +254,6 @@ fn void_fun(a : i32, b : void, c : i32) {
}
)SOURCE", "OK\n");
- add_simple_case("void struct fields", R"SOURCE(
-import "std.zig";
-struct Foo {
- a : void,
- b : i32,
- c : void,
-}
-pub fn main(args: [][]u8) -> %void {
- const foo = Foo {
- .a = void{},
- .b = 1,
- .c = void{},
- };
- if (foo.b != 1) {
- %%stdout.printf("BAD\n");
- }
- if (@sizeof(Foo) != 4) {
- %%stdout.printf("BAD\n");
- }
- %%stdout.printf("OK\n");
-}
-
- )SOURCE", "OK\n");
-
- add_simple_case("void arrays", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- var array: [4]void = undefined;
- array[0] = void{};
- array[1] = array[2];
- if (@sizeof(@typeof(array)) != 0) {
- %%stdout.printf("BAD sizeof\n");
- }
- if (array.len != 4) {
- %%stdout.printf("BAD len\n");
- }
- %%stdout.printf("OK\n");
-}
- )SOURCE", "OK\n");
-
-
add_simple_case("mutable local variables", R"SOURCE(
import "std.zig";
@@ -414,27 +312,6 @@ pub fn main(args: [][]u8) -> %void {
)SOURCE", "Hello, world!\n");
- add_simple_case("a + b + c", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- if (false || false || false) { %%stdout.printf("BAD 1\n"); }
- if (true && true && false) { %%stdout.printf("BAD 2\n"); }
- if (1 | 2 | 4 != 7) { %%stdout.printf("BAD 3\n"); }
- if (3 ^ 6 ^ 8 != 13) { %%stdout.printf("BAD 4\n"); }
- if (7 & 14 & 28 != 4) { %%stdout.printf("BAD 5\n"); }
- if (9 << 1 << 2 != 9 << 3) { %%stdout.printf("BAD 6\n"); }
- if (90 >> 1 >> 2 != 90 >> 3) { %%stdout.printf("BAD 7\n"); }
- if (100 - 1 + 1000 != 1099) { %%stdout.printf("BAD 8\n"); }
- if (5 * 4 / 2 % 3 != 1) { %%stdout.printf("BAD 9\n"); }
- if (i32(i32(5)) != 5) { %%stdout.printf("BAD 10\n"); }
- if (!!false) { %%stdout.printf("BAD 11\n"); }
- if (i32(7) != --(i32(7))) { %%stdout.printf("BAD 12\n"); }
-
- %%stdout.printf("OK\n");
-}
- )SOURCE", "OK\n");
-
add_simple_case("short circuit", R"SOURCE(
import "std.zig";
@@ -729,39 +606,6 @@ pub fn main(args: [][]u8) -> %void {
}
)SOURCE", "loop\nloop\nloop\nloop\n");
- add_simple_case("maybe type", R"SOURCE(
-import "std.zig";
-pub fn main(args: [][]u8) -> %void {
- const x : ?bool = true;
-
- if (const y ?= x) {
- if (y) {
- %%stdout.printf("x is true\n");
- } else {
- %%stdout.printf("x is false\n");
- }
- } else {
- %%stdout.printf("x is none\n");
- }
-
- const next_x : ?i32 = null;
-
- const z = next_x ?? 1234;
-
- if (z != 1234) {
- %%stdout.printf("BAD\n");
- }
-
- const final_x : ?i32 = 13;
-
- const num = final_x ?? unreachable{};
-
- if (num != 13) {
- %%stdout.printf("BAD\n");
- }
-}
- )SOURCE", "x is true\n");
-
add_simple_case("implicit cast after unreachable", R"SOURCE(
import "std.zig";
pub fn main(args: [][]u8) -> %void {
@@ -971,73 +815,6 @@ fn print_ok(val: @typeof(x)) -> @typeof(foo) {
const foo : i32 = 0;
)SOURCE", "OK\n");
- add_simple_case("enum type", R"SOURCE(
-import "std.zig";
-
-struct Point {
- x: u64,
- y: u64,
-}
-
-enum Foo {
- One: i32,
- Two: Point,
- Three: void,
-}
-
-enum Bar {
- A,
- B,
- C,
- D,
-}
-
-pub fn main(args: [][]u8) -> %void {
- const foo1 = Foo.One(13);
- const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, });
- const bar = Bar.B;
-
- if (bar != Bar.B) {
- %%stdout.printf("BAD 1\n");
- }
-
- if (@member_count(Foo) != 3) {
- %%stdout.printf("BAD 2\n");
- }
-
- if (@member_count(Bar) != 4) {
- %%stdout.printf("BAD 3\n");
- }
-
- if (@sizeof(Foo) != 24) {
- %%stdout.printf("BAD 4\n");
- }
- if (@sizeof(Bar) != 1) {
- %%stdout.printf("BAD 5\n");
- }
-
- %%stdout.printf("OK\n");
-}
- )SOURCE", "OK\n");
-
- add_simple_case("array literal", R"SOURCE(
-import "std.zig";
-
-pub fn main(args: [][]u8) -> %void {
- const HEX_MULT = []u16{4096, 256, 16, 1};
-
- if (HEX_MULT.len != 4) {
- %%stdout.printf("BAD\n");
- }
-
- if (HEX_MULT[1] != 256) {
- %%stdout.printf("BAD\n");
- }
-
- %%stdout.printf("OK\n");
-}
- )SOURCE", "OK\n");
-
add_simple_case("nested arrays", R"SOURCE(
import "std.zig";
@@ -1092,23 +869,6 @@ fn fn3() -> u32 {7}
fn fn4() -> u32 {8}
)SOURCE", "5\n6\n7\n8\n");
- add_simple_case("const number literal", R"SOURCE(
-import "std.zig";
-
-const ten = 10;
-
-pub fn main(args: [][]u8) -> %void {
- const one = 1;
- const eleven = ten + one;
-
- if (eleven != 11) {
- %%stdout.printf("BAD\n");
- }
-
- %%stdout.printf("OK\n");
-}
- )SOURCE", "OK\n");
-
add_simple_case("statically initialized struct", R"SOURCE(
import "std.zig";
struct Foo {
@@ -1139,21 +899,6 @@ pub fn main(args: [][]u8) -> %void {
}
)SOURCE", "OK\n");
- add_simple_case("error values", R"SOURCE(
-import "std.zig";
-error err1;
-error err2;
-pub fn main(args: [][]u8) -> %void {
- const a = i32(error.err1);
- const b = i32(error.err2);
- if (a == b) {
- %%stdout.printf("BAD\n");
- }
-
- %%stdout.printf("OK\n");
-}
- )SOURCE", "OK\n");
-
add_simple_case("return with implicit cast from while loop", R"SOURCE(
import "std.zig";
pub fn main(args: [][]u8) -> %void {
@@ -1988,6 +1733,13 @@ struct Foo {
}
fn get() -> isize { 1 }
)SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression");
+
+
+ add_compile_fail_case("unnecessary if statement", R"SOURCE(
+fn f() {
+ if (true) { }
+}
+ )SOURCE", 1, ".tmp_source.zig:3:9: error: condition is always true; unnecessary if statement");
}
//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig
@@ -5,7 +5,6 @@ fn empty_function() {}
-
/**
* multi line doc comment
*/
@@ -19,6 +18,200 @@ fn comments() {
fn comments_f1(s: []u8) {}
+#attribute("test")
+fn if_statements() {
+ should_be_equal(1, 1);
+ first_eql_third(2, 1, 2);
+}
+fn should_be_equal(a: i32, b: i32) {
+ if (a != b) {
+ unreachable{};
+ } else {
+ return;
+ }
+}
+fn first_eql_third(a: i32, b: i32, c: i32) {
+ if (a == b) {
+ unreachable{};
+ } else if (b == c) {
+ unreachable{};
+ } else if (a == c) {
+ return;
+ } else {
+ unreachable{};
+ }
+}
+
+
+#attribute("test")
+fn local_variables() {
+ test_loc_vars(2);
+}
+fn test_loc_vars(b: i32) {
+ const a: i32 = 1;
+ if (a + b != 3) unreachable{};
+}
+
+#attribute("test")
+fn bool_literals() {
+ should_be_true(true);
+ should_be_false(false);
+}
+fn should_be_true(b: bool) {
+ if (!b) unreachable{};
+}
+fn should_be_false(b: bool) {
+ if (b) unreachable{};
+}
+
+
+#attribute("test")
+fn separate_block_scopes() {
+ {
+ const no_conflict : i32 = 5;
+ assert(no_conflict == 5);
+ }
+
+ const c = {
+ const no_conflict = i32(10);
+ no_conflict
+ };
+ assert(c == 10);
+}
+
+
+#attribute("test")
+fn void_struct_fields() {
+ const foo = VoidStructFieldsFoo {
+ .a = void{},
+ .b = 1,
+ .c = void{},
+ };
+ assert(foo.b == 1);
+ assert(@sizeof(VoidStructFieldsFoo) == 4);
+}
+struct VoidStructFieldsFoo {
+ a : void,
+ b : i32,
+ c : void,
+}
+
+
+#attribute("test")
+fn void_arrays() {
+ var array: [4]void = undefined;
+ array[0] = void{};
+ array[1] = array[2];
+ assert(@sizeof(@typeof(array)) == 0);
+ assert(array.len == 4);
+}
+
+
+#attribute("test")
+fn three_expr_in_a_row() {
+ assert_false(false || false || false);
+ assert_false(true && true && false);
+ assert_false(1 | 2 | 4 != 7);
+ assert_false(3 ^ 6 ^ 8 != 13);
+ assert_false(7 & 14 & 28 != 4);
+ assert_false(9 << 1 << 2 != 9 << 3);
+ assert_false(90 >> 1 >> 2 != 90 >> 3);
+ assert_false(100 - 1 + 1000 != 1099);
+ assert_false(5 * 4 / 2 % 3 != 1);
+ assert_false(i32(i32(5)) != 5);
+ assert_false(!!false);
+ assert_false(i32(7) != --(i32(7)));
+}
+fn assert_false(b: bool) {
+ assert(!b);
+}
+
+
+#attribute("test")
+fn maybe_type() {
+ const x : ?bool = true;
+
+ if (const y ?= x) {
+ if (y) {
+ // OK
+ } else {
+ unreachable{};
+ }
+ } else {
+ unreachable{};
+ }
+
+ const next_x : ?i32 = null;
+
+ const z = next_x ?? 1234;
+
+ assert(z == 1234);
+
+ const final_x : ?i32 = 13;
+
+ const num = final_x ?? unreachable{};
+
+ assert(num == 13);
+}
+
+
+#attribute("test")
+fn enum_type() {
+ const foo1 = EnumTypeFoo.One(13);
+ const foo2 = EnumTypeFoo.Two(EnumType { .x = 1234, .y = 5678, });
+ const bar = EnumTypeBar.B;
+
+ assert(bar == EnumTypeBar.B);
+ assert(@member_count(EnumTypeFoo) == 3);
+ assert(@member_count(EnumTypeBar) == 4);
+ assert(@sizeof(EnumTypeFoo) == 24);
+ assert(@sizeof(EnumTypeBar) == 1);
+}
+struct EnumType {
+ x: u64,
+ y: u64,
+}
+enum EnumTypeFoo {
+ One: i32,
+ Two: EnumType,
+ Three: void,
+}
+enum EnumTypeBar {
+ A,
+ B,
+ C,
+ D,
+}
+
+
+#attribute("test")
+fn array_literal() {
+ const HEX_MULT = []u16{4096, 256, 16, 1};
+
+ assert(HEX_MULT.len == 4);
+ assert(HEX_MULT[1] == 256);
+}
+
+
+#attribute("test")
+fn const_number_literal() {
+ const one = 1;
+ const eleven = ten + one;
+
+ assert(eleven == 11);
+}
+const ten = 10;
+
+
+#attribute("test")
+fn error_values() {
+ const a = i32(error.err1);
+ const b = i32(error.err2);
+ assert(a != b);
+}
+error err1;
+error err2;
+
#attribute("test")
@@ -42,11 +235,14 @@ fn call_struct_field(foo: Foo) -> i32 {
#attribute("test")
fn redefinition_of_error_values_allowed() {
- if (error.AnError == error.SecondError) unreachable{}
+ should_be_not_equal(error.AnError, error.SecondError);
}
error AnError;
error AnError;
error SecondError;
+fn should_be_not_equal(a: error, b: error) {
+ if (a == b) unreachable{}
+}
@@ -98,14 +294,14 @@ fn continue_in_for_loop() {
fn cast_bool_to_int() {
const t = true;
const f = false;
- if (i32(t) != i32(1)) unreachable{}
- if (i32(f) != i32(0)) unreachable{}
+ assert(i32(t) == i32(1));
+ assert(i32(f) == i32(0));
non_const_cast_bool_to_int(t, f);
}
fn non_const_cast_bool_to_int(t: bool, f: bool) {
- if (i32(t) != i32(1)) unreachable{}
- if (i32(f) != i32(0)) unreachable{}
+ assert(i32(t) == i32(1));
+ assert(i32(f) == i32(0));
}
@@ -240,7 +436,7 @@ fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {
#attribute("test")
fn builtin_const_eval() {
const x : i32 = @const_eval(1 + 2 + 3);
- if (x != @const_eval(6)) unreachable{};
+ assert(x == @const_eval(6));
}
#attribute("test")
@@ -279,3 +475,10 @@ struct ArrayDotLenConstExpr {
y: [@const_eval(some_array.len)]u8,
}
const some_array = []u8 {0, 1, 2, 3};
+
+
+
+
+fn assert(b: bool) {
+ if (!b) unreachable{}
+}