authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 17:11:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-15 17:11:57-07:00
log423ee0689be4f93b2613a5e42e7411887a9a46ad
tree3e5e1c02c7e108968e699eb5d7c4844b1c9cd9a4
parent8a570c458bcf62bc3d882f8d253f75ec6d3fd719

add implicit casting support


5 files changed, 200 insertions(+), 84 deletions(-)

README.md+2
...@@ -39,6 +39,8 @@ compromises backward compatibility....@@ -39,6 +39,8 @@ compromises backward compatibility.
39 provide a tag or sha1).39 provide a tag or sha1).
40 * Include documentation generator.40 * Include documentation generator.
41 * Shebang line OK so language can be used for "scripting" as well.41 * Shebang line OK so language can be used for "scripting" as well.
42 * No null pointer. Convenient syntax for dealing with a maybe type so that
43 null pointer is not missed.
4244
43### Current Status45### Current Status
4446
src/analyze.cpp+126-65
...@@ -551,22 +551,127 @@ static TypeTableEntry *get_return_type(BlockContext *context) {...@@ -551,22 +551,127 @@ static TypeTableEntry *get_return_type(BlockContext *context) {
551 return return_type_node->codegen_node->data.type_node.entry;551 return return_type_node->codegen_node->data.type_node.entry;
552}552}
553553
554static void check_type_compatibility(CodeGen *g, AstNode *node,554static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node,
555 TypeTableEntry *type1, TypeTableEntry *type2)
556{
557 if (type1->id == TypeTableEntryIdInvalid ||
558 type2->id == TypeTableEntryIdInvalid)
559 {
560 return type1;
561 } else if (type1->id == TypeTableEntryIdUnreachable) {
562 return type2;
563 } else if (type2->id == TypeTableEntryIdUnreachable) {
564 return type1;
565 } else if (type1->id == TypeTableEntryIdInt &&
566 type2->id == TypeTableEntryIdInt &&
567 type1->data.integral.is_signed == type2->data.integral.is_signed)
568 {
569 return (type1->size_in_bits > type2->size_in_bits) ? type1 : type2;
570 } else if (type1->id == TypeTableEntryIdFloat &&
571 type2->id == TypeTableEntryIdFloat)
572 {
573 return (type1->size_in_bits > type2->size_in_bits) ? type1 : type2;
574 } else if (type1->id == TypeTableEntryIdArray &&
575 type2->id == TypeTableEntryIdArray &&
576 type1 == type2)
577 {
578 return type1;
579 } else if (type1 == type2) {
580 return type1;
581 }
582
583 add_node_error(g, node,
584 buf_sprintf("ambiguous expression type: '%s' vs '%s'",
585 buf_ptr(&type1->name), buf_ptr(&type2->name)));
586
587 return g->builtin_types.entry_invalid;
588}
589
590static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) {
591 NumLit num_lit = literal_type->data.num_lit.kind;
592 uint64_t lit_size_in_bits = num_lit_bit_count(num_lit);
593
594 switch (other_type->id) {
595 case TypeTableEntryIdInvalid:
596 case TypeTableEntryIdNumberLiteral:
597 zig_unreachable();
598 case TypeTableEntryIdVoid:
599 case TypeTableEntryIdBool:
600 case TypeTableEntryIdUnreachable:
601 case TypeTableEntryIdPointer:
602 case TypeTableEntryIdArray:
603 case TypeTableEntryIdStruct:
604 return false;
605 case TypeTableEntryIdInt:
606 if (is_num_lit_unsigned(num_lit)) {
607 return lit_size_in_bits <= other_type->size_in_bits;
608 } else {
609 return false;
610 }
611 case TypeTableEntryIdFloat:
612 if (is_num_lit_float(num_lit)) {
613 return lit_size_in_bits <= other_type->size_in_bits;
614 } else {
615 return false;
616 }
617 }
618 zig_unreachable();
619}
620
621static TypeTableEntry *resolve_type_compatibility(CodeGen *g, AstNode *node,
555 TypeTableEntry *expected_type, TypeTableEntry *actual_type)622 TypeTableEntry *expected_type, TypeTableEntry *actual_type)
556{623{
557 if (expected_type == nullptr)624 if (expected_type == nullptr)
558 return; // anything will do625 return actual_type; // anything will do
559 if (expected_type == actual_type)626 if (expected_type == actual_type)
560 return; // match627 return expected_type; // match
561 if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid)628 if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid)
562 return; // already complained629 return expected_type; // already complained
563 if (actual_type->id == TypeTableEntryIdUnreachable)630 if (actual_type->id == TypeTableEntryIdUnreachable)
564 return; // sorry toots; gotta run. good luck with that expected type.631 return actual_type; // sorry toots; gotta run. good luck with that expected type.
632
633 if (actual_type->id == TypeTableEntryIdNumberLiteral &&
634 num_lit_fits_in_other_type(g, actual_type, expected_type))
635 {
636 return expected_type;
637 }
638
639 // implicit widening conversion
640 if (expected_type->id == TypeTableEntryIdInt &&
641 actual_type->id == TypeTableEntryIdInt &&
642 expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
643 expected_type->size_in_bits > actual_type->size_in_bits)
644 {
645 node->codegen_node->expr_node.cast_type = expected_type;
646 node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten;
647 return expected_type;
648 }
565649
566 add_node_error(g, node,650 add_node_error(g, node,
567 buf_sprintf("expected type '%s', got '%s'",651 buf_sprintf("expected type '%s', got '%s'",
568 buf_ptr(&expected_type->name),652 buf_ptr(&expected_type->name),
569 buf_ptr(&actual_type->name)));653 buf_ptr(&actual_type->name)));
654
655 return g->builtin_types.entry_invalid;
656}
657
658static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, AstNode *parent_node,
659 AstNode *child1, AstNode *child2,
660 TypeTableEntry *type1, TypeTableEntry *type2)
661{
662 assert(type1);
663 assert(type2);
664
665 TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2);
666
667 if (parent_type->id == TypeTableEntryIdInvalid) {
668 return parent_type;
669 }
670
671 resolve_type_compatibility(g, child1, parent_type, type1);
672 resolve_type_compatibility(g, child2, parent_type, type2);
673
674 return parent_type;
570}675}
571676
572BlockContext *new_block_context(AstNode *node, BlockContext *parent) {677BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
...@@ -624,39 +729,6 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF...@@ -624,39 +729,6 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF
624 *out_i = -1;729 *out_i = -1;
625}730}
626731
627static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) {
628 NumLit num_lit = literal_type->data.num_lit.kind;
629 uint64_t lit_size_in_bits = num_lit_bit_count(num_lit);
630
631 switch (other_type->id) {
632 case TypeTableEntryIdInvalid:
633 case TypeTableEntryIdNumberLiteral:
634 zig_unreachable();
635 case TypeTableEntryIdVoid:
636 case TypeTableEntryIdBool:
637 case TypeTableEntryIdUnreachable:
638 case TypeTableEntryIdPointer:
639 case TypeTableEntryIdArray:
640 case TypeTableEntryIdStruct:
641 return false;
642 case TypeTableEntryIdInt:
643 if (is_num_lit_unsigned(num_lit)) {
644
645 return lit_size_in_bits <= other_type->size_in_bits;
646 } else {
647 return false;
648 }
649 case TypeTableEntryIdFloat:
650 if (is_num_lit_float(num_lit)) {
651 return lit_size_in_bits <= other_type->size_in_bits;
652 } else {
653 return false;
654 }
655 }
656 zig_unreachable();
657}
658
659
660static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,732static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
661 AstNode *node)733 AstNode *node)
662{734{
...@@ -1125,19 +1197,10 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry...@@ -1125,19 +1197,10 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
1125 buf_sprintf("number literal too large to be represented in any type"));1197 buf_sprintf("number literal too large to be represented in any type"));
1126 return g->builtin_types.entry_invalid;1198 return g->builtin_types.entry_invalid;
1127 } else if (expected_type) {1199 } else if (expected_type) {
1128 if (expected_type->id == TypeTableEntryIdInvalid) {1200 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
1129 return g->builtin_types.entry_invalid;1201 assert(!codegen_num_lit->resolved_type);
1130 } else if (num_lit_fits_in_other_type(g, num_lit_type, expected_type)) {1202 codegen_num_lit->resolved_type = resolve_type_compatibility(g, node, expected_type, num_lit_type);
1131 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;1203 return codegen_num_lit->resolved_type;
1132 assert(!codegen_num_lit->resolved_type);
1133 codegen_num_lit->resolved_type = expected_type;
1134
1135 return expected_type;
1136 } else {
1137 add_node_error(g, node, buf_sprintf("expected type '%s', got '%s'",
1138 buf_ptr(&expected_type->name), buf_ptr(&num_lit_type->name)));
1139 return g->builtin_types.entry_invalid;
1140 }
1141 } else {1204 } else {
1142 return num_lit_type;1205 return num_lit_type;
1143 }1206 }
...@@ -1154,6 +1217,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1154,6 +1217,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1154 BlockContext *child_context = new_block_context(node, context);1217 BlockContext *child_context = new_block_context(node, context);
1155 node->codegen_node->data.block_node.block_context = child_context;1218 node->codegen_node->data.block_node.block_context = child_context;
1156 return_type = g->builtin_types.entry_void;1219 return_type = g->builtin_types.entry_void;
1220
1157 for (int i = 0; i < node->data.block.statements.length; i += 1) {1221 for (int i = 0; i < node->data.block.statements.length; i += 1) {
1158 AstNode *child = node->data.block.statements.at(i);1222 AstNode *child = node->data.block.statements.at(i);
1159 if (child->type == NodeTypeLabel) {1223 if (child->type == NodeTypeLabel) {
...@@ -1172,7 +1236,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1172,7 +1236,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1172 add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));1236 add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));
1173 break;1237 break;
1174 }1238 }
1175 return_type = analyze_expression(g, import, child_context, nullptr, child);1239 bool is_last = (i == node->data.block.statements.length - 1);
1240 TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
1241 return_type = analyze_expression(g, import, child_context, passed_expected_type, child);
1176 }1242 }
1177 break;1243 break;
1178 }1244 }
...@@ -1194,7 +1260,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1194,7 +1260,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1194 actual_return_type = g->builtin_types.entry_invalid;1260 actual_return_type = g->builtin_types.entry_invalid;
1195 }1261 }
11961262
1197 check_type_compatibility(g, node, expected_return_type, actual_return_type);1263 resolve_type_compatibility(g, node, expected_return_type, actual_return_type);
1198 } else {1264 } else {
1199 add_node_error(g, node, buf_sprintf("return expression outside function definition"));1265 add_node_error(g, node, buf_sprintf("return expression outside function definition"));
1200 }1266 }
...@@ -1387,22 +1453,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1387,22 +1453,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1387 else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node);1453 else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node);
1388 } else {1454 } else {
1389 else_type = g->builtin_types.entry_void;1455 else_type = g->builtin_types.entry_void;
1456 else_type = resolve_type_compatibility(g, node, expected_type, else_type);
1390 }1457 }
13911458
13921459
1393 TypeTableEntry *primary_type;1460 if (expected_type) {
1394 TypeTableEntry *other_type;1461 return_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
1395 if (then_type->id == TypeTableEntryIdUnreachable) {
1396 primary_type = else_type;
1397 other_type = then_type;
1398 } else {1462 } else {
1399 primary_type = then_type;1463 return_type = resolve_peer_type_compatibility(g, node,
1400 other_type = else_type;1464 node->data.if_expr.then_block, node->data.if_expr.else_node,
1465 then_type, else_type);
1401 }1466 }
1402
1403 check_type_compatibility(g, node, primary_type, other_type);
1404 check_type_compatibility(g, node, expected_type, other_type);
1405 return_type = primary_type;
1406 break;1467 break;
1407 }1468 }
1408 case NodeTypeDirective:1469 case NodeTypeDirective:
...@@ -1421,7 +1482,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1421,7 +1482,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1421 zig_unreachable();1482 zig_unreachable();
1422 }1483 }
1423 assert(return_type);1484 assert(return_type);
1424 check_type_compatibility(g, node, expected_type, return_type);1485 resolve_type_compatibility(g, node, expected_type, return_type);
14251486
1426 node->codegen_node->expr_node.type_entry = return_type;1487 node->codegen_node->expr_node.type_entry = return_type;
1427 node->codegen_node->expr_node.block_context = context;1488 node->codegen_node->expr_node.block_context = context;
src/analyze.hpp+12-6
...@@ -145,6 +145,7 @@ struct CodeGen {...@@ -145,6 +145,7 @@ struct CodeGen {
145 TypeTableEntry *entry_bool;145 TypeTableEntry *entry_bool;
146 TypeTableEntry *entry_u8;146 TypeTableEntry *entry_u8;
147 TypeTableEntry *entry_u64;147 TypeTableEntry *entry_u64;
148 TypeTableEntry *entry_i8;
148 TypeTableEntry *entry_i32;149 TypeTableEntry *entry_i32;
149 TypeTableEntry *entry_i64;150 TypeTableEntry *entry_i64;
150 TypeTableEntry *entry_isize;151 TypeTableEntry *entry_isize;
...@@ -230,12 +231,6 @@ struct FnDefNode {...@@ -230,12 +231,6 @@ struct FnDefNode {
230 bool skip;231 bool skip;
231};232};
232233
233struct ExprNode {
234 TypeTableEntry *type_entry;
235 // the context in which this expression is evaluated.
236 // for blocks, this points to the containing scope, not the block's own scope for its children.
237 BlockContext *block_context;
238};
239234
240struct AssignNode {235struct AssignNode {
241 VariableTableEntry *var_entry;236 VariableTableEntry *var_entry;
...@@ -268,6 +263,17 @@ struct CastNode {...@@ -268,6 +263,17 @@ struct CastNode {
268 LLVMValueRef ptr;263 LLVMValueRef ptr;
269};264};
270265
266struct ExprNode {
267 TypeTableEntry *type_entry;
268 // the context in which this expression is evaluated.
269 // for blocks, this points to the containing scope, not the block's own scope for its children.
270 BlockContext *block_context;
271
272 // may be null for no cast
273 TypeTableEntry *cast_type;
274 CastNode implicit_cast;
275};
276
271struct NumberLiteralNode {277struct NumberLiteralNode {
272 TypeTableEntry *resolved_type;278 TypeTableEntry *resolved_type;
273};279};
src/codegen.cpp+49-11
...@@ -274,16 +274,9 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {...@@ -274,16 +274,9 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
274 zig_unreachable();274 zig_unreachable();
275}275}
276276
277static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {277static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val,
278 assert(node->type == NodeTypeCastExpr);278 TypeTableEntry *actual_type, TypeTableEntry *wanted_type, CastNode *cast_node)
279279{
280 LLVMValueRef expr_val = gen_expr(g, node->data.cast_expr.expr);
281
282 TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
283 TypeTableEntry *wanted_type = get_expr_type(node);
284
285 CastNode *cast_node = &node->codegen_node->data.cast_node;
286
287 switch (cast_node->op) {280 switch (cast_node->op) {
288 case CastOpNothing:281 case CastOpNothing:
289 return expr_val;282 return expr_val;
...@@ -327,6 +320,20 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {...@@ -327,6 +320,20 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
327 zig_unreachable();320 zig_unreachable();
328}321}
329322
323static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
324 assert(node->type == NodeTypeCastExpr);
325
326 LLVMValueRef expr_val = gen_expr(g, node->data.cast_expr.expr);
327
328 TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
329 TypeTableEntry *wanted_type = get_expr_type(node);
330
331 CastNode *cast_node = &node->codegen_node->data.cast_node;
332
333 return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node);
334
335}
336
330static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,337static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
331 LLVMValueRef val1, LLVMValueRef val2,338 LLVMValueRef val1, LLVMValueRef val2,
332 TypeTableEntry *op1_type, TypeTableEntry *op2_type,339 TypeTableEntry *op1_type, TypeTableEntry *op2_type,
...@@ -871,7 +878,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {...@@ -871,7 +878,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
871 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");878 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
872}879}
873880
874static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {881static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
875 switch (node->type) {882 switch (node->type) {
876 case NodeTypeBinOpExpr:883 case NodeTypeBinOpExpr:
877 return gen_bin_op_expr(g, node);884 return gen_bin_op_expr(g, node);
...@@ -1022,6 +1029,22 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -1022,6 +1029,22 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
1022 zig_unreachable();1029 zig_unreachable();
1023}1030}
10241031
1032static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
1033 LLVMValueRef val = gen_expr_no_cast(g, node);
1034
1035 if (node->type == NodeTypeVoid) {
1036 return val;
1037 }
1038
1039 assert(node->codegen_node);
1040
1041 TypeTableEntry *actual_type = node->codegen_node->expr_node.type_entry;
1042 TypeTableEntry *cast_type = node->codegen_node->expr_node.cast_type;
1043
1044 return cast_type ? gen_bare_cast(g, node, val, actual_type, cast_type,
1045 &node->codegen_node->expr_node.implicit_cast) : val;
1046}
1047
1025static void build_label_blocks(CodeGen *g, AstNode *block_node) {1048static void build_label_blocks(CodeGen *g, AstNode *block_node) {
1026 assert(block_node->type == NodeTypeBlock);1049 assert(block_node->type == NodeTypeBlock);
1027 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {1050 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
...@@ -1322,6 +1345,19 @@ static void define_builtin_types(CodeGen *g) {...@@ -1322,6 +1345,19 @@ static void define_builtin_types(CodeGen *g) {
1322 g->builtin_types.entry_u64 = entry;1345 g->builtin_types.entry_u64 = entry;
1323 }1346 }
1324 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);1347 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
1348 {
1349 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1350 entry->type_ref = LLVMInt8Type();
1351 buf_init_from_str(&entry->name, "i8");
1352 entry->size_in_bits = 8;
1353 entry->align_in_bits = 8;
1354 entry->data.integral.is_signed = true;
1355 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1356 entry->size_in_bits, entry->align_in_bits,
1357 LLVMZigEncoding_DW_ATE_signed());
1358 g->type_table.put(&entry->name, entry);
1359 g->builtin_types.entry_i8 = entry;
1360 }
1325 {1361 {
1326 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);1362 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1327 entry->type_ref = LLVMInt32Type();1363 entry->type_ref = LLVMInt32Type();
...@@ -1951,6 +1987,8 @@ void codegen_link(CodeGen *g, const char *out_file) {...@@ -1951,6 +1987,8 @@ void codegen_link(CodeGen *g, const char *out_file) {
1951 fprintf(stderr, "ld failed with return code %d\n", return_code);1987 fprintf(stderr, "ld failed with return code %d\n", return_code);
1952 fprintf(stderr, "%s\n", buf_ptr(&ld_stderr));1988 fprintf(stderr, "%s\n", buf_ptr(&ld_stderr));
1953 exit(1);1989 exit(1);
1990 } else if (buf_len(&ld_stderr)) {
1991 fprintf(stderr, "%s\n", buf_ptr(&ld_stderr));
1954 }1992 }
19551993
1956 if (g->out_type == OutTypeLib) {1994 if (g->out_type == OutTypeLib) {
test/run_tests.cpp+11-2
...@@ -56,7 +56,7 @@ static TestCase *add_simple_case(const char *case_name, const char *source, cons...@@ -56,7 +56,7 @@ static TestCase *add_simple_case(const char *case_name, const char *source, cons
56 test_case->compiler_args.append(tmp_exe_path);56 test_case->compiler_args.append(tmp_exe_path);
57 test_case->compiler_args.append("--release");57 test_case->compiler_args.append("--release");
58 test_case->compiler_args.append("--strip");58 test_case->compiler_args.append("--strip");
59 test_case->compiler_args.append("--verbose");59 //test_case->compiler_args.append("--verbose");
60 test_case->compiler_args.append("--color");60 test_case->compiler_args.append("--color");
61 test_case->compiler_args.append("on");61 test_case->compiler_args.append("on");
6262
...@@ -86,7 +86,7 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source...@@ -86,7 +86,7 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source
86 test_case->compiler_args.append(tmp_exe_path);86 test_case->compiler_args.append(tmp_exe_path);
87 test_case->compiler_args.append("--release");87 test_case->compiler_args.append("--release");
88 test_case->compiler_args.append("--strip");88 test_case->compiler_args.append("--strip");
89 test_case->compiler_args.append("--verbose");89 //test_case->compiler_args.append("--verbose");
9090
91 test_cases.append(test_case);91 test_cases.append(test_case);
9292
...@@ -788,6 +788,15 @@ fn f() {...@@ -788,6 +788,15 @@ fn f() {
788 x = 1;788 x = 1;
789}789}
790 )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant variable");790 )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant variable");
791
792
793 add_compile_fail_case("missing else clause", R"SOURCE(
794fn f() {
795 const x : i32 = if true { 1 };
796 const y = if true { 1 as i32 };
797}
798 )SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'",
799 ".tmp_source.zig:4:15: error: ambiguous expression type: 'i32' vs 'void'");
791}800}
792801
793static void print_compiler_invocation(TestCase *test_case) {802static void print_compiler_invocation(TestCase *test_case) {