authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-06 16:36:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-06 16:36:49-07:00
log65a03c5859e57820d2c28ad2952dda3fd4ac7d9c
treecbf8162ed73547c27a535fe21ebea20888625639
parent34a7e6fdb362cb7be1067b7d1fc110eb2f323c51

implement %defer and ?defer

see #110

4 files changed, 113 insertions(+), 47 deletions(-)

src/all_types.hpp+10
......@@ -78,8 +78,18 @@ struct ConstExprValue {
7878 } data;
7979};
8080
81enum ReturnKnowledge {
82 ReturnKnowledgeUnknown,
83 ReturnKnowledgeKnownError,
84 ReturnKnowledgeKnownNonError,
85 ReturnKnowledgeKnownNull,
86 ReturnKnowledgeKnownNonNull,
87 ReturnKnowledgeSkipDefers,
88};
89
8190struct Expr {
8291 TypeTableEntry *type_entry;
92 ReturnKnowledge return_knowledge;
8393
8494 LLVMValueRef const_llvm_val;
8595 ConstExprValue const_val;
src/analyze.cpp+9-37
......@@ -3693,11 +3693,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
36933693 // explicit cast from child type of maybe type to maybe type
36943694 if (wanted_type->id == TypeTableEntryIdMaybe) {
36953695 if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
3696 get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonNull;
36963697 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpMaybeWrap, true);
36973698 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
36983699 actual_type->id == TypeTableEntryIdNumLitFloat)
36993700 {
37003701 if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.maybe.child_type)) {
3702 get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonNull;
37013703 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpMaybeWrap, true);
37023704 } else {
37033705 return g->builtin_types.entry_invalid;
......@@ -3708,11 +3710,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
37083710 // explicit cast from child type of error type to error type
37093711 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
37103712 if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
3713 get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonError;
37113714 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrorWrap, true);
37123715 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
37133716 actual_type->id == TypeTableEntryIdNumLitFloat)
37143717 {
37153718 if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.error.child_type)) {
3719 get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonError;
37163720 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrorWrap, true);
37173721 } else {
37183722 return g->builtin_types.entry_invalid;
......@@ -3724,6 +3728,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
37243728 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
37253729 actual_type->id == TypeTableEntryIdPureError)
37263730 {
3731 get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownError;
37273732 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPureErrorWrap, false);
37283733 }
37293734
......@@ -4602,44 +4607,11 @@ static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, Block
46024607
46034608 node->data.defer.child_block = new_block_context(node, parent_context);
46044609
4605 switch (node->data.defer.kind) {
4606 case ReturnKindUnconditional:
4607 {
4608 TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
4609 node->data.defer.expr);
4610 validate_voided_expr(g, node->data.defer.expr, resolved_type);
4610 TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
4611 node->data.defer.expr);
4612 validate_voided_expr(g, node->data.defer.expr, resolved_type);
46114613
4612 return g->builtin_types.entry_void;
4613 }
4614 case ReturnKindError:
4615 {
4616 TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
4617 node->data.defer.expr);
4618 if (resolved_type->id == TypeTableEntryIdInvalid) {
4619 // OK
4620 } else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
4621 // OK
4622 } else {
4623 add_node_error(g, node->data.defer.expr,
4624 buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));
4625 }
4626 return g->builtin_types.entry_void;
4627 }
4628 case ReturnKindMaybe:
4629 {
4630 TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
4631 node->data.defer.expr);
4632 if (resolved_type->id == TypeTableEntryIdInvalid) {
4633 // OK
4634 } else if (resolved_type->id == TypeTableEntryIdMaybe) {
4635 // OK
4636 } else {
4637 add_node_error(g, node->data.defer.expr,
4638 buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
4639 }
4640 return g->builtin_types.entry_void;
4641 }
4642 }
4614 return g->builtin_types.entry_void;
46434615}
46444616
46454617static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
src/codegen.cpp+58-10
......@@ -483,6 +483,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
483483 }
484484 case CastOpPureErrorWrap:
485485 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
486
486487 if (!type_has_bits(wanted_type->data.error.child_type)) {
487488 return expr_val;
488489 } else {
......@@ -1593,18 +1594,48 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
15931594 return phi;
15941595}
15951596
1596static void gen_defers_for_block(CodeGen *g, BlockContext *inner_block, BlockContext *outer_block) {
1597static void gen_defers_for_block(CodeGen *g, BlockContext *inner_block, BlockContext *outer_block,
1598 bool gen_error_defers, bool gen_maybe_defers)
1599{
15971600 while (inner_block != outer_block) {
1598 if (inner_block->node->type == NodeTypeDefer) {
1601 if (inner_block->node->type == NodeTypeDefer &&
1602 ((inner_block->node->data.defer.kind == ReturnKindUnconditional) ||
1603 (gen_error_defers && inner_block->node->data.defer.kind == ReturnKindError) ||
1604 (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe)))
1605 {
15991606 gen_expr(g, inner_block->node->data.defer.expr);
16001607 }
16011608 inner_block = inner_block->parent;
16021609 }
16031610}
16041611
1605static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {
1606 gen_defers_for_block(g, source_node->block_context,
1607 source_node->block_context->fn_entry->fn_def_node->block_context);
1612static int get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
1613 int result = 0;
1614 while (inner_block != outer_block) {
1615 if (inner_block->node->type == NodeTypeDefer &&
1616 (inner_block->node->data.defer.kind == ReturnKindError ||
1617 inner_block->node->data.defer.kind == ReturnKindMaybe))
1618 {
1619 result += 1;
1620 }
1621 inner_block = inner_block->parent;
1622 }
1623 return result;
1624}
1625
1626static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value, ReturnKnowledge rk) {
1627 BlockContext *defer_inner_block = source_node->block_context;
1628 BlockContext *defer_outer_block = source_node->block_context->fn_entry->fn_def_node->block_context;
1629 if (rk == ReturnKnowledgeUnknown) {
1630 if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) {
1631 // generate branching code that checks the return value and generates defers
1632 // if the return value is error
1633 zig_panic("TODO");
1634 }
1635 } else if (rk != ReturnKnowledgeSkipDefers) {
1636 gen_defers_for_block(g, defer_inner_block, defer_outer_block,
1637 rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
1638 }
16081639
16091640 TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
16101641 if (handle_is_ptr(return_type)) {
......@@ -1628,7 +1659,23 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
16281659 switch (node->data.return_expr.kind) {
16291660 case ReturnKindUnconditional:
16301661 {
1631 return gen_return(g, node, value);
1662 Expr *expr = get_resolved_expr(param_node);
1663 if (expr->const_val.ok) {
1664 if (value_type->id == TypeTableEntryIdErrorUnion) {
1665 if (expr->const_val.data.x_err.err) {
1666 expr->return_knowledge = ReturnKnowledgeKnownError;
1667 } else {
1668 expr->return_knowledge = ReturnKnowledgeKnownNonError;
1669 }
1670 } else if (value_type->id == TypeTableEntryIdMaybe) {
1671 if (expr->const_val.data.x_maybe) {
1672 expr->return_knowledge = ReturnKnowledgeKnownNonNull;
1673 } else {
1674 expr->return_knowledge = ReturnKnowledgeKnownNull;
1675 }
1676 }
1677 }
1678 return gen_return(g, node, value, expr->return_knowledge);
16321679 }
16331680 case ReturnKindError:
16341681 {
......@@ -1653,7 +1700,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
16531700 LLVMPositionBuilderAtEnd(g->builder, return_block);
16541701 TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
16551702 if (return_type->id == TypeTableEntryIdPureError) {
1656 gen_return(g, node, err_val);
1703 gen_return(g, node, err_val, ReturnKnowledgeKnownError);
16571704 } else if (return_type->id == TypeTableEntryIdErrorUnion) {
16581705 if (type_has_bits(return_type->data.error.child_type)) {
16591706 assert(g->cur_ret_ptr);
......@@ -1663,7 +1710,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
16631710 LLVMBuildStore(g->builder, err_val, tag_ptr);
16641711 LLVMBuildRetVoid(g->builder);
16651712 } else {
1666 gen_return(g, node, err_val);
1713 gen_return(g, node, err_val, ReturnKnowledgeKnownError);
16671714 }
16681715 } else {
16691716 zig_unreachable();
......@@ -1834,10 +1881,11 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
18341881 return nullptr;
18351882 }
18361883
1837 gen_defers_for_block(g, block_node->data.block.nested_block, block_node->data.block.child_block);
1884 gen_defers_for_block(g, block_node->data.block.nested_block, block_node->data.block.child_block,
1885 false, false);
18381886
18391887 if (implicit_return_type) {
1840 return gen_return(g, block_node, return_value);
1888 return gen_return(g, block_node, return_value, ReturnKnowledgeSkipDefers);
18411889 } else {
18421890 return return_value;
18431891 }
test/run_tests.cpp+36
......@@ -1545,6 +1545,42 @@ pub fn main(args: [][]u8) -> %void {
15451545}
15461546 )SOURCE", "before\ndefer2\ndefer1\n");
15471547
1548
1549 add_simple_case("%defer and it fails", R"SOURCE(
1550import "std.zig";
1551pub fn main(args: [][]u8) -> %void {
1552 do_test() %% return;
1553}
1554fn do_test() -> %void {
1555 %%stdout.printf("before\n");
1556 defer %%stdout.printf("defer1\n");
1557 %defer %%stdout.printf("deferErr\n");
1558 %return its_gonna_fail();
1559 defer %%stdout.printf("defer3\n");
1560 %%stdout.printf("after\n");
1561}
1562error IToldYouItWouldFail;
1563fn its_gonna_fail() -> %void {
1564 return error.IToldYouItWouldFail;
1565}
1566 )SOURCE", "before\ndeferErr\ndefer1\n");
1567
1568
1569 add_simple_case("%defer and it passes", R"SOURCE(
1570import "std.zig";
1571pub fn main(args: [][]u8) -> %void {
1572 do_test() %% return;
1573}
1574fn do_test() -> %void {
1575 %%stdout.printf("before\n");
1576 defer %%stdout.printf("defer1\n");
1577 %defer %%stdout.printf("deferErr\n");
1578 %return its_gonna_pass();
1579 defer %%stdout.printf("defer3\n");
1580 %%stdout.printf("after\n");
1581}
1582fn its_gonna_pass() -> %void { }
1583 )SOURCE", "before\nafter\ndefer3\ndefer1\n");
15481584}
15491585
15501586