authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-02 00:06:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-02 00:06:06-07:00
log9a8851515b8aeac1adcea38094a45e3260e7522c
treedc1671648ae9ce7ab065ca36e012c4625c2880b0
parentb3ac5c16ecc8dd9da661dcb9d15a6c36a8e4167b

basic maybe type working


6 files changed, 267 insertions(+), 100 deletions(-)

doc/vim/syntax/zig.vim+1-1
......@@ -19,7 +19,7 @@ syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
1919
2020syn keyword zigBoolean true false
2121
22syn match zigOperator display "\%(+\|-\|/\|*\|=\|\^\|&\||\|!\|>\|<\|%\)=\?"
22syn match zigOperator display "\%(+\|-\|/\|*\|=\|\^\|&\|?\||\|!\|>\|<\|%\)=\?"
2323syn match zigOperator display "&&\|||"
2424syn match zigArrowCharacter display "->"
2525
example/maybe_type/main.zig+1-1
......@@ -2,7 +2,7 @@ export executable "maybe_type";
22
33use "std.zig";
44
5fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
5pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
66 const x : ?bool = true;
77
88 if (const y ?= x) {
src/analyze.cpp+61-7
......@@ -137,13 +137,44 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
137137 return child_type->maybe_parent;
138138 } else {
139139 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
140 // TODO entry->type_ref
140 // create a struct with a boolean whether this is the null value
141 assert(child_type->type_ref);
142 LLVMTypeRef elem_types[] = {
143 child_type->type_ref,
144 LLVMInt1Type(),
145 };
146 entry->type_ref = LLVMStructType(elem_types, 2, false);
141147 buf_resize(&entry->name, 0);
142148 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
143 // TODO entry->size_in_bits
144 // TODO entry->align_in_bits
149 entry->size_in_bits = child_type->size_in_bits + 8;
150 entry->align_in_bits = child_type->align_in_bits;
145151 assert(child_type->di_type);
146 // TODO entry->di_type
152
153
154 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
155 LLVMZigDIFile *di_file = nullptr;
156 unsigned line = 0;
157 entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
158 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
159 compile_unit_scope, di_file, line);
160
161 LLVMZigDIType *di_element_types[] = {
162 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
163 "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
164 child_type->di_type),
165 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
166 "maybe", di_file, line, 8, 8, 8, 0,
167 child_type->di_type),
168 };
169 LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
170 compile_unit_scope,
171 buf_ptr(&entry->name),
172 di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
173 nullptr, di_element_types, 2, 0, nullptr, "");
174
175 LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
176 entry->di_type = replacement_di_type;
177
147178 entry->data.maybe.child_type = child_type;
148179
149180 g->type_table.put(&entry->name, entry);
......@@ -814,13 +845,35 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
814845 return expected_type;
815846 }
816847
848 if (expected_type->id == TypeTableEntryIdMaybe &&
849 actual_type->id == TypeTableEntryIdMaybe)
850 {
851 TypeTableEntry *expected_child = expected_type->data.maybe.child_type;
852 TypeTableEntry *actual_child = actual_type->data.maybe.child_type;
853 return resolve_type_compatibility(g, context, node, expected_child, actual_child);
854 }
855
856 // implicit conversion from non maybe type to maybe type
857 if (expected_type->id == TypeTableEntryIdMaybe) {
858 TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
859 expected_type->data.maybe.child_type, actual_type);
860 if (resolved_type->id == TypeTableEntryIdInvalid) {
861 return resolved_type;
862 }
863 node->codegen_node->expr_node.implicit_maybe_cast.op = CastOpMaybeWrap;
864 node->codegen_node->expr_node.implicit_maybe_cast.after_type = expected_type;
865 node->codegen_node->expr_node.implicit_maybe_cast.source_node = node;
866 context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_maybe_cast);
867 return expected_type;
868 }
869
817870 // implicit widening conversion
818871 if (expected_type->id == TypeTableEntryIdInt &&
819872 actual_type->id == TypeTableEntryIdInt &&
820873 expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
821874 expected_type->size_in_bits > actual_type->size_in_bits)
822875 {
823 node->codegen_node->expr_node.implicit_cast.type = expected_type;
876 node->codegen_node->expr_node.implicit_cast.after_type = expected_type;
824877 node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten;
825878 node->codegen_node->expr_node.implicit_cast.source_node = node;
826879 return expected_type;
......@@ -831,7 +884,7 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
831884 actual_type->id == TypeTableEntryIdArray &&
832885 actual_type->data.array.child_type == g->builtin_types.entry_u8)
833886 {
834 node->codegen_node->expr_node.implicit_cast.type = expected_type;
887 node->codegen_node->expr_node.implicit_cast.after_type = expected_type;
835888 node->codegen_node->expr_node.implicit_cast.op = CastOpArrayToString;
836889 node->codegen_node->expr_node.implicit_cast.source_node = node;
837890 context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_cast);
......@@ -1077,7 +1130,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
10771130
10781131 CastNode *cast_node = &node->codegen_node->data.cast_node;
10791132 cast_node->source_node = node;
1080 cast_node->type = wanted_type;
1133 cast_node->after_type = wanted_type;
10811134
10821135 // special casing this for now, TODO think about casting and do a general solution
10831136 if (wanted_type == g->builtin_types.entry_isize &&
......@@ -1489,6 +1542,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
14891542 assert(node->type == NodeTypeIfVarExpr);
14901543
14911544 BlockContext *child_context = new_block_context(node, context);
1545 node->codegen_node->data.if_var_node.block_context = child_context;
14921546
14931547 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);
14941548
src/analyze.hpp+10-3
......@@ -272,10 +272,11 @@ struct FieldAccessNode {
272272};
273273
274274enum CastOp {
275 CastOpNothing,
275276 CastOpPtrToInt,
276277 CastOpIntWidenOrShorten,
277278 CastOpArrayToString,
278 CastOpNothing,
279 CastOpMaybeWrap,
279280};
280281
281282struct CastNode {
......@@ -283,7 +284,7 @@ struct CastNode {
283284 // if op is CastOpArrayToString, this will be a pointer to
284285 // the string struct on the stack
285286 LLVMValueRef ptr;
286 TypeTableEntry *type;
287 TypeTableEntry *after_type;
287288 AstNode *source_node;
288289};
289290
......@@ -294,7 +295,8 @@ struct ExprNode {
294295 BlockContext *block_context;
295296
296297 // may be null for no cast
297 CastNode implicit_cast;
298 CastNode implicit_cast; // happens first
299 CastNode implicit_maybe_cast; // happens second
298300};
299301
300302struct NumberLiteralNode {
......@@ -315,6 +317,10 @@ struct StructValExprNode {
315317 AstNode *source_node;
316318};
317319
320struct IfVarNode {
321 BlockContext *block_context;
322};
323
318324struct CodeGenNode {
319325 union {
320326 TypeNode type_node; // for NodeTypeType
......@@ -330,6 +336,7 @@ struct CodeGenNode {
330336 VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
331337 StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
332338 StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
339 IfVarNode if_var_node; // for NodeTypeStructValueExpr
333340 } data;
334341 ExprNode expr_node; // for all the expression nodes
335342};
src/codegen.cpp+176-88
......@@ -65,6 +65,11 @@ void codegen_set_libc_path(CodeGen *g, Buf *libc_path) {
6565static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
6666static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
6767static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
68static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
69 BlockContext *block_context, bool unwrap_maybe, LLVMValueRef *init_val);
70static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
71 LLVMValueRef target_ref, LLVMValueRef value,
72 TypeTableEntry *op1_type, TypeTableEntry *op2_type);
6873
6974
7075static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
......@@ -132,7 +137,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
132137}
133138
134139static TypeTableEntry *get_expr_type(AstNode *node) {
135 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.type;
140 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.after_type;
136141 return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;
137142}
138143
......@@ -367,6 +372,22 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v
367372 switch (cast_node->op) {
368373 case CastOpNothing:
369374 return expr_val;
375 case CastOpMaybeWrap:
376 {
377 assert(cast_node->ptr);
378 assert(wanted_type->id == TypeTableEntryIdMaybe);
379
380 add_debug_source_node(g, node);
381 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, "");
382 gen_assign_raw(g, node, BinOpTypeAssign,
383 val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type);
384
385 add_debug_source_node(g, node);
386 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, "");
387 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
388
389 return cast_node->ptr;
390 }
370391 case CastOpPtrToInt:
371392 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
372393 case CastOpIntWidenOrShorten:
......@@ -423,34 +444,33 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
423444
424445}
425446
426static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
447static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
427448 LLVMValueRef val1, LLVMValueRef val2,
428449 TypeTableEntry *op1_type, TypeTableEntry *op2_type,
429 AstNode *node)
450 BinOpType bin_op)
430451{
431 assert(node->type == NodeTypeBinOpExpr);
432452 assert(op1_type == op2_type);
433453
434 switch (node->data.bin_op_expr.bin_op) {
454 switch (bin_op) {
435455 case BinOpTypeBinOr:
436456 case BinOpTypeAssignBitOr:
437 add_debug_source_node(g, node);
457 add_debug_source_node(g, source_node);
438458 return LLVMBuildOr(g->builder, val1, val2, "");
439459 case BinOpTypeBinXor:
440460 case BinOpTypeAssignBitXor:
441 add_debug_source_node(g, node);
461 add_debug_source_node(g, source_node);
442462 return LLVMBuildXor(g->builder, val1, val2, "");
443463 case BinOpTypeBinAnd:
444464 case BinOpTypeAssignBitAnd:
445 add_debug_source_node(g, node);
465 add_debug_source_node(g, source_node);
446466 return LLVMBuildAnd(g->builder, val1, val2, "");
447467 case BinOpTypeBitShiftLeft:
448468 case BinOpTypeAssignBitShiftLeft:
449 add_debug_source_node(g, node);
469 add_debug_source_node(g, source_node);
450470 return LLVMBuildShl(g->builder, val1, val2, "");
451471 case BinOpTypeBitShiftRight:
452472 case BinOpTypeAssignBitShiftRight:
453 add_debug_source_node(g, node);
473 add_debug_source_node(g, source_node);
454474 if (op1_type->id == TypeTableEntryIdInt) {
455475 return LLVMBuildAShr(g->builder, val1, val2, "");
456476 } else {
......@@ -458,7 +478,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
458478 }
459479 case BinOpTypeAdd:
460480 case BinOpTypeAssignPlus:
461 add_debug_source_node(g, node);
481 add_debug_source_node(g, source_node);
462482 if (op1_type->id == TypeTableEntryIdFloat) {
463483 return LLVMBuildFAdd(g->builder, val1, val2, "");
464484 } else {
......@@ -466,7 +486,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
466486 }
467487 case BinOpTypeSub:
468488 case BinOpTypeAssignMinus:
469 add_debug_source_node(g, node);
489 add_debug_source_node(g, source_node);
470490 if (op1_type->id == TypeTableEntryIdFloat) {
471491 return LLVMBuildFSub(g->builder, val1, val2, "");
472492 } else {
......@@ -474,7 +494,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
474494 }
475495 case BinOpTypeMult:
476496 case BinOpTypeAssignTimes:
477 add_debug_source_node(g, node);
497 add_debug_source_node(g, source_node);
478498 if (op1_type->id == TypeTableEntryIdFloat) {
479499 return LLVMBuildFMul(g->builder, val1, val2, "");
480500 } else {
......@@ -482,7 +502,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
482502 }
483503 case BinOpTypeDiv:
484504 case BinOpTypeAssignDiv:
485 add_debug_source_node(g, node);
505 add_debug_source_node(g, source_node);
486506 if (op1_type->id == TypeTableEntryIdFloat) {
487507 return LLVMBuildFDiv(g->builder, val1, val2, "");
488508 } else {
......@@ -495,7 +515,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
495515 }
496516 case BinOpTypeMod:
497517 case BinOpTypeAssignMod:
498 add_debug_source_node(g, node);
518 add_debug_source_node(g, source_node);
499519 if (op1_type->id == TypeTableEntryIdFloat) {
500520 return LLVMBuildFRem(g->builder, val1, val2, "");
501521 } else {
......@@ -530,7 +550,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
530550
531551 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
532552 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
533 return gen_arithmetic_bin_op(g, val1, val2, op1_type, op2_type, node);
553 return gen_arithmetic_bin_op(g, node, val1, val2, op1_type, op2_type, node->data.bin_op_expr.bin_op);
534554
535555}
536556
......@@ -660,7 +680,7 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
660680static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest,
661681 TypeTableEntry *type_entry)
662682{
663 assert(type_entry->id == TypeTableEntryIdStruct);
683 assert(type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdMaybe);
664684
665685 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
666686
......@@ -679,6 +699,30 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValu
679699 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
680700}
681701
702static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
703 LLVMValueRef target_ref, LLVMValueRef value,
704 TypeTableEntry *op1_type, TypeTableEntry *op2_type)
705{
706 if (op1_type->id == TypeTableEntryIdStruct) {
707 assert(op2_type->id == TypeTableEntryIdStruct);
708 assert(op1_type == op2_type);
709 assert(bin_op == BinOpTypeAssign);
710
711 return gen_struct_memcpy(g, source_node, value, target_ref, op1_type);
712 }
713
714 if (bin_op != BinOpTypeAssign) {
715 assert(source_node->type == NodeTypeBinOpExpr);
716 add_debug_source_node(g, source_node->data.bin_op_expr.op1);
717 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
718
719 value = gen_arithmetic_bin_op(g, source_node, left_value, value, op1_type, op2_type, bin_op);
720 }
721
722 add_debug_source_node(g, source_node);
723 return LLVMBuildStore(g->builder, value, target_ref);
724}
725
682726static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
683727 assert(node->type == NodeTypeBinOpExpr);
684728
......@@ -692,23 +736,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
692736
693737 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
694738
695 if (op1_type->id == TypeTableEntryIdStruct) {
696 assert(op2_type->id == TypeTableEntryIdStruct);
697 assert(op1_type == op2_type);
698 assert(node->data.bin_op_expr.bin_op == BinOpTypeAssign);
699
700 return gen_struct_memcpy(g, node, value, target_ref, op1_type);
701 }
702
703 if (node->data.bin_op_expr.bin_op != BinOpTypeAssign) {
704 add_debug_source_node(g, node->data.bin_op_expr.op1);
705 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
706
707 value = gen_arithmetic_bin_op(g, left_value, value, op1_type, op2_type, node);
708 }
709
710 add_debug_source_node(g, node);
711 return LLVMBuildStore(g->builder, value, target_ref);
739 return gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
712740}
713741
714742static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
......@@ -769,18 +797,14 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
769797 }
770798}
771799
772static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
773 assert(node->type == NodeTypeIfBoolExpr);
774 assert(node->data.if_bool_expr.condition);
775 assert(node->data.if_bool_expr.then_block);
776
777 LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
778
779 TypeTableEntry *then_type = get_expr_type(node->data.if_bool_expr.then_block);
800static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,
801 AstNode *then_node, AstNode *else_node)
802{
803 TypeTableEntry *then_type = get_expr_type(then_node);
780804 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&
781805 then_type->id != TypeTableEntryIdVoid);
782806
783 if (node->data.if_bool_expr.else_node) {
807 if (else_node) {
784808 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
785809 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
786810 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
......@@ -788,13 +812,13 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
788812 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
789813
790814 LLVMPositionBuilderAtEnd(g->builder, then_block);
791 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_bool_expr.then_block);
792 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)
815 LLVMValueRef then_expr_result = gen_expr(g, then_node);
816 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
793817 LLVMBuildBr(g->builder, endif_block);
794818
795819 LLVMPositionBuilderAtEnd(g->builder, else_block);
796 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_bool_expr.else_node);
797 if (get_expr_type(node->data.if_bool_expr.else_node)->id != TypeTableEntryIdUnreachable)
820 LLVMValueRef else_expr_result = gen_expr(g, else_node);
821 if (get_expr_type(else_node)->id != TypeTableEntryIdUnreachable)
798822 LLVMBuildBr(g->builder, endif_block);
799823
800824 LLVMPositionBuilderAtEnd(g->builder, endif_block);
......@@ -818,17 +842,49 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
818842 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
819843
820844 LLVMPositionBuilderAtEnd(g->builder, then_block);
821 gen_expr(g, node->data.if_bool_expr.then_block);
822 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)
845 gen_expr(g, then_node);
846 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
823847 LLVMBuildBr(g->builder, endif_block);
824848
825849 LLVMPositionBuilderAtEnd(g->builder, endif_block);
826850 return nullptr;
827851}
828852
853static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
854 assert(node->type == NodeTypeIfBoolExpr);
855 assert(node->data.if_bool_expr.condition);
856 assert(node->data.if_bool_expr.then_block);
857
858 LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
859
860 return gen_if_bool_expr_raw(g, node, cond_value,
861 node->data.if_bool_expr.then_block,
862 node->data.if_bool_expr.else_node);
863}
864
829865static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
830866 assert(node->type == NodeTypeIfVarExpr);
831 zig_panic("TODO gen_if_var_expr");
867 assert(node->data.if_var_expr.var_decl.expr);
868
869 BlockContext *old_block_context = g->cur_block_context;
870 BlockContext *new_block_context = node->codegen_node->data.if_var_node.block_context;
871
872 LLVMValueRef init_val;
873 gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, new_block_context, true, &init_val);
874
875 // test if value is the maybe state
876 add_debug_source_node(g, node);
877 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
878 LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
879
880 g->cur_block_context = new_block_context;
881
882 LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value,
883 node->data.if_var_expr.then_block,
884 node->data.if_var_expr.else_node);
885
886 g->cur_block_context = old_block_context;
887 return return_value;
832888}
833889
834890static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
......@@ -1058,6 +1114,55 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
10581114 return LLVMBuildBr(g->builder, dest_block);
10591115}
10601116
1117static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
1118 BlockContext *block_context, bool unwrap_maybe, LLVMValueRef *init_value)
1119{
1120 VariableTableEntry *variable = find_variable(block_context, &var_decl->symbol);
1121
1122 assert(variable);
1123 assert(variable->is_ptr);
1124
1125 if (var_decl->expr) {
1126 *init_value = gen_expr(g, var_decl->expr);
1127 } else {
1128 *init_value = LLVMConstNull(variable->type->type_ref);
1129 }
1130 if (variable->type->id == TypeTableEntryIdVoid) {
1131 return nullptr;
1132 } else {
1133 LLVMValueRef store_instr;
1134 LLVMValueRef value;
1135 if (unwrap_maybe) {
1136 assert(var_decl->expr);
1137 add_debug_source_node(g, source_node);
1138 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, *init_value, 0, "");
1139 // TODO if it's a struct we might not want to load the pointer
1140 value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1141 } else {
1142 value = *init_value;
1143 }
1144 if ((variable->type->id == TypeTableEntryIdStruct || variable->type->id == TypeTableEntryIdMaybe) &&
1145 var_decl->expr)
1146 {
1147 store_instr = gen_struct_memcpy(g, source_node, value, variable->value_ref, variable->type);
1148 } else {
1149 add_debug_source_node(g, source_node);
1150 store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);
1151 }
1152
1153 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
1154 g->cur_block_context->di_scope);
1155 LLVMZigInsertDeclare(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc, store_instr);
1156 return nullptr;
1157 }
1158}
1159
1160static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
1161 LLVMValueRef init_val;
1162 return gen_var_decl_raw(g, node, &node->data.variable_declaration,
1163 node->codegen_node->expr_node.block_context, false, &init_val);
1164}
1165
10611166static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
10621167 switch (node->type) {
10631168 case NodeTypeBinOpExpr:
......@@ -1065,38 +1170,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
10651170 case NodeTypeReturnExpr:
10661171 return gen_return_expr(g, node);
10671172 case NodeTypeVariableDeclaration:
1068 {
1069 VariableTableEntry *variable = find_variable(
1070 node->codegen_node->expr_node.block_context,
1071 &node->data.variable_declaration.symbol);
1072
1073 assert(variable);
1074 assert(variable->is_ptr);
1075
1076 LLVMValueRef value;
1077 if (node->data.variable_declaration.expr) {
1078 value = gen_expr(g, node->data.variable_declaration.expr);
1079 } else {
1080 value = LLVMConstNull(variable->type->type_ref);
1081 }
1082 if (variable->type->id == TypeTableEntryIdVoid) {
1083 return nullptr;
1084 } else {
1085 LLVMValueRef store_instr;
1086 if (variable->type->id == TypeTableEntryIdStruct && node->data.variable_declaration.expr) {
1087 store_instr = gen_struct_memcpy(g, node, value, variable->value_ref, variable->type);
1088 } else {
1089 add_debug_source_node(g, node);
1090 store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);
1091 }
1092
1093 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(node->line + 1, node->column + 1,
1094 g->cur_block_context->di_scope);
1095 LLVMZigInsertDeclare(g->dbuilder, variable->value_ref, variable->di_loc_var,
1096 debug_loc, store_instr);
1097 return nullptr;
1098 }
1099 }
1173 return gen_var_decl_expr(g, node);
11001174 case NodeTypeCastExpr:
11011175 return gen_cast_expr(g, node);
11021176 case NodeTypePrefixOpExpr:
......@@ -1174,7 +1248,9 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
11741248 assert(variable->value_ref);
11751249 if (variable->type->id == TypeTableEntryIdArray) {
11761250 return variable->value_ref;
1177 } else if (variable->type->id == TypeTableEntryIdStruct) {
1251 } else if (variable->type->id == TypeTableEntryIdStruct ||
1252 variable->type->id == TypeTableEntryIdMaybe)
1253 {
11781254 return variable->value_ref;
11791255 } else {
11801256 add_debug_source_node(g, node);
......@@ -1225,6 +1301,12 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
12251301 zig_unreachable();
12261302}
12271303
1304static LLVMValueRef gen_cast_node(CodeGen *g, AstNode *node, LLVMValueRef val, TypeTableEntry *before_type,
1305 CastNode *cast_node)
1306{
1307 return cast_node->after_type ? gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node) : val;
1308}
1309
12281310static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
12291311 LLVMValueRef val = gen_expr_no_cast(g, node);
12301312
......@@ -1234,11 +1316,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
12341316
12351317 assert(node->codegen_node);
12361318
1237 TypeTableEntry *actual_type = node->codegen_node->expr_node.type_entry;
1238 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.type;
1319 {
1320 TypeTableEntry *before_type = node->codegen_node->expr_node.type_entry;
1321 val = gen_cast_node(g, node, val, before_type, &node->codegen_node->expr_node.implicit_cast);
1322 }
1323
1324 {
1325 TypeTableEntry *before_type = node->codegen_node->expr_node.implicit_cast.after_type;
1326 val = gen_cast_node(g, node, val, before_type, &node->codegen_node->expr_node.implicit_maybe_cast);
1327 }
12391328
1240 return cast_type ? gen_bare_cast(g, node, val, actual_type, cast_type,
1241 &node->codegen_node->expr_node.implicit_cast) : val;
1329 return val;
12421330}
12431331
12441332static void build_label_blocks(CodeGen *g, AstNode *block_node) {
......@@ -1460,7 +1548,7 @@ static void do_code_gen(CodeGen *g) {
14601548 for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {
14611549 CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i);
14621550 add_debug_source_node(g, cast_node->source_node);
1463 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->type->type_ref, "");
1551 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, "");
14641552 }
14651553
14661554 // allocate structs which are struct value expressions
test/run_tests.cpp+18
......@@ -674,6 +674,24 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
674674 return 0;
675675}
676676 )SOURCE", "loop\nloop\nloop\nloop\n");
677
678 add_simple_case("maybe type", R"SOURCE(
679use "std.zig";
680export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
681 const x : ?bool = true;
682
683 if (const y ?= x) {
684 if (y) {
685 print_str("x is true\n");
686 } else {
687 print_str("x is false\n");
688 }
689 } else {
690 print_str("x is none\n");
691 }
692 return 0;
693}
694 )SOURCE", "x is true\n");
677695}
678696
679697////////////////////////////////////////////////////////////////////////////////////