authorgravatar for buzdav2@gmail.comfoobles <buzdav2@gmail.com> 2020-05-09 15:32:12-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-29 18:46:09-04:00
log51682717d773aa4bdee89bc67cab08dc9b4bcc15
treeae6222e43438e2fbc936fab72deb9a340d0f3ba3
parentf107d654e073a7cc0c2e920ee6fac9b2b34dba0c

Support equality comparison for optional to non-optional (?T ==/!= T)

extracted function ir_try_evaluate_bin_op_const extracted type_is_self_comparable function renamed ir_try_evaluate_bin_op_const to ir_try_evaluate_bin_op_cmp_const implemented analysis of ?T == T added ir_set_cursor_at_end_and_append_basic_block_gen use build_br_gen and ir_set_cursor_at_end_and_append_block_gen added ir_append_basic_block_gen removed include of all_types in ir.cpp extracted compile-time and runtime evaluation of cmp_optional_non_optional to separate functions closes #5390 closes #1332

3 files changed, 312 insertions(+), 85 deletions(-)

src/ir.cpp+256-85
......@@ -15,6 +15,7 @@
1515#include "softfloat.hpp"
1616#include "util.hpp"
1717#include "mem_list.hpp"
18#include "all_types.hpp"
1819
1920#include <errno.h>
2021
......@@ -5099,6 +5100,17 @@ static void ir_set_cursor_at_end(IrBuilderSrc *irb, IrBasicBlockSrc *basic_block
50995100 irb->current_basic_block = basic_block;
51005101}
51015102
5103static void ir_append_basic_block_gen(IrBuilderGen *irb, IrBasicBlockGen *bb) {
5104 assert(!bb->already_appended);
5105 bb->already_appended = true;
5106 irb->exec->basic_block_list.append(bb);
5107}
5108
5109static void ir_set_cursor_at_end_and_append_block_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) {
5110 ir_append_basic_block_gen(irb, basic_block);
5111 ir_set_cursor_at_end_gen(irb, basic_block);
5112}
5113
51025114static void ir_set_cursor_at_end_and_append_block(IrBuilderSrc *irb, IrBasicBlockSrc *basic_block) {
51035115 basic_block->index = irb->exec->basic_block_list.length;
51045116 irb->exec->basic_block_list.append(basic_block);
......@@ -13137,12 +13149,11 @@ static void ir_start_next_bb(IrAnalyze *ira) {
1313713149
1313813150static void ir_finish_bb(IrAnalyze *ira) {
1313913151 if (!ira->new_irb.current_basic_block->already_appended) {
13140 ira->new_irb.current_basic_block->already_appended = true;
13152 ir_append_basic_block_gen(&ira->new_irb, ira->new_irb.current_basic_block);
1314113153 if (ira->codegen->verbose_ir) {
1314213154 fprintf(stderr, "append new bb %s_%" PRIu32 "\n", ira->new_irb.current_basic_block->name_hint,
1314313155 ira->new_irb.current_basic_block->debug_id);
1314413156 }
13145 ira->new_irb.exec->basic_block_list.append(ira->new_irb.current_basic_block);
1314613157 }
1314713158 ira->instruction_index += 1;
1314813159 while (ira->instruction_index < ira->old_irb.current_basic_block->instruction_list.length) {
......@@ -15849,12 +15860,12 @@ static void set_optional_payload(ZigValue *opt_val, ZigValue *payload) {
1584915860}
1585015861
1585115862static IrInstGen *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type,
15852 ZigValue *op1_val, ZigValue *op2_val, IrInstSrcBinOp *bin_op_instruction, IrBinOp op_id,
15863 ZigValue *op1_val, ZigValue *op2_val, IrInst *source_instr, IrBinOp op_id,
1585315864 bool one_possible_value)
1585415865{
1585515866 if (op1_val->special == ConstValSpecialUndef ||
1585615867 op2_val->special == ConstValSpecialUndef)
15857 return ir_const_undef(ira, &bin_op_instruction->base.base, resolved_type);
15868 return ir_const_undef(ira, source_instr, resolved_type);
1585815869 if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
1585915870 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
1586015871 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
......@@ -15874,7 +15885,7 @@ static IrInstGen *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type,
1587415885 cmp_result = CmpEQ;
1587515886 }
1587615887 bool answer = resolve_cmp_op_id(op_id, cmp_result);
15877 return ir_const_bool(ira, &bin_op_instruction->base.base, answer);
15888 return ir_const_bool(ira, source_instr, answer);
1587815889 }
1587915890 } else {
1588015891 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
......@@ -15886,11 +15897,55 @@ static IrInstGen *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type,
1588615897 } else {
1588715898 zig_unreachable();
1588815899 }
15889 return ir_const_bool(ira, &bin_op_instruction->base.base, answer);
15900 return ir_const_bool(ira, source_instr, answer);
1589015901 }
1589115902 zig_unreachable();
1589215903}
1589315904
15905static IrInstGen *ir_try_evaluate_bin_op_cmp_const(IrAnalyze *ira, IrInst *source_instr, IrInstGen *op1, IrInstGen *op2,
15906 ZigType *resolved_type, IrBinOp op_id)
15907{
15908 assert(op1->value->type == resolved_type && op2->value->type == resolved_type);
15909 bool one_possible_value;
15910 switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
15911 case OnePossibleValueInvalid:
15912 return ira->codegen->invalid_inst_gen;
15913 case OnePossibleValueYes:
15914 one_possible_value = true;
15915 break;
15916 case OnePossibleValueNo:
15917 one_possible_value = false;
15918 break;
15919 }
15920
15921 if (one_possible_value || (instr_is_comptime(op1) && instr_is_comptime(op2))) {
15922 ZigValue *op1_val = one_possible_value ? op1->value : ir_resolve_const(ira, op1, UndefBad);
15923 if (op1_val == nullptr)
15924 return ira->codegen->invalid_inst_gen;
15925 ZigValue *op2_val = one_possible_value ? op2->value : ir_resolve_const(ira, op2, UndefBad);
15926 if (op2_val == nullptr)
15927 return ira->codegen->invalid_inst_gen;
15928 if (resolved_type->id != ZigTypeIdVector)
15929 return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, source_instr, op_id, one_possible_value);
15930 IrInstGen *result = ir_const(ira, source_instr,
15931 get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool));
15932 result->value->data.x_array.data.s_none.elements =
15933 ira->codegen->pass1_arena->allocate<ZigValue>(resolved_type->data.vector.len);
15934
15935 expand_undef_array(ira->codegen, result->value);
15936 for (size_t i = 0;i < resolved_type->data.vector.len;i++) {
15937 IrInstGen *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type,
15938 &op1_val->data.x_array.data.s_none.elements[i],
15939 &op2_val->data.x_array.data.s_none.elements[i],
15940 source_instr, op_id, one_possible_value);
15941 copy_const_val(ira->codegen, &result->value->data.x_array.data.s_none.elements[i], cur_res->value);
15942 }
15943 return result;
15944 } else {
15945 return nullptr;
15946 }
15947}
15948
1589415949// Returns ErrorNotLazy when the value cannot be determined
1589515950static Error lazy_cmp_zero(CodeGen *codegen, AstNode *source_node, ZigValue *val, Cmp *result) {
1589615951 Error err;
......@@ -16425,6 +16480,188 @@ static IrInstGen *ir_analyze_bin_op_cmp_numeric(IrAnalyze *ira, IrInst *source_i
1642516480 return ir_build_bin_op_gen(ira, source_instr, result_type, op_id, casted_op1, casted_op2, true);
1642616481}
1642716482
16483static bool type_is_self_comparable(ZigType *ty, bool is_equality_cmp) {
16484 if (type_is_numeric(ty)) {
16485 return true;
16486 }
16487 switch (ty->id) {
16488 case ZigTypeIdInvalid:
16489 zig_unreachable();
16490
16491 case ZigTypeIdComptimeFloat:
16492 case ZigTypeIdComptimeInt:
16493 case ZigTypeIdInt:
16494 case ZigTypeIdFloat:
16495 zig_unreachable(); // handled with the type_is_numeric check above
16496
16497 case ZigTypeIdVector:
16498 // Not every case is handled by the type_is_numeric check above,
16499 // vectors of bool trigger this code path
16500 case ZigTypeIdBool:
16501 case ZigTypeIdMetaType:
16502 case ZigTypeIdVoid:
16503 case ZigTypeIdErrorSet:
16504 case ZigTypeIdFn:
16505 case ZigTypeIdOpaque:
16506 case ZigTypeIdBoundFn:
16507 case ZigTypeIdEnum:
16508 case ZigTypeIdEnumLiteral:
16509 case ZigTypeIdAnyFrame:
16510 return is_equality_cmp;
16511
16512 case ZigTypeIdPointer:
16513 return is_equality_cmp || (ty->data.pointer.ptr_len == PtrLenC);
16514
16515 case ZigTypeIdUnreachable:
16516 case ZigTypeIdArray:
16517 case ZigTypeIdStruct:
16518 case ZigTypeIdUndefined:
16519 case ZigTypeIdNull:
16520 case ZigTypeIdErrorUnion:
16521 case ZigTypeIdUnion:
16522 case ZigTypeIdFnFrame:
16523 return false;
16524
16525 case ZigTypeIdOptional:
16526 return is_equality_cmp && get_src_ptr_type(ty) != nullptr;
16527 }
16528 zig_unreachable();
16529}
16530
16531static IrInstGen *ir_try_evaluate_cmp_optional_non_optional_const(IrAnalyze *ira, IrInst *source_instr, ZigType *child_type,
16532 IrInstGen *optional, IrInstGen *non_optional, IrBinOp op_id)
16533{
16534 assert(optional->value->type->id == ZigTypeIdOptional);
16535 assert(optional->value->type->data.maybe.child_type == non_optional->value->type);
16536 assert(non_optional->value->type == child_type);
16537 assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
16538
16539 if (instr_is_comptime(optional) && instr_is_comptime(non_optional)) {
16540 ZigValue *optional_val = ir_resolve_const(ira, optional, UndefBad);
16541 if (!optional_val) {
16542 return ira->codegen->invalid_inst_gen;
16543 }
16544
16545 ZigValue *non_optional_val = ir_resolve_const(ira, non_optional, UndefBad);
16546 if (!non_optional_val) {
16547 return ira->codegen->invalid_inst_gen;
16548 }
16549
16550 if (!optional_value_is_null(optional_val)) {
16551 IrInstGen *optional_unwrapped = ir_analyze_optional_value_payload_value(ira, source_instr, optional, false);
16552 if (type_is_invalid(optional_unwrapped->value->type)) {
16553 return ira->codegen->invalid_inst_gen;
16554 }
16555
16556 IrInstGen *ret = ir_try_evaluate_bin_op_cmp_const(ira, source_instr, optional_unwrapped, non_optional, child_type, op_id);
16557 assert(ret != nullptr);
16558 return ret;
16559 }
16560 return ir_const_bool(ira, source_instr, (op_id != IrBinOpCmpEq));
16561 } else {
16562 return nullptr;
16563 }
16564}
16565
16566static IrInstGen *ir_evaluate_cmp_optional_non_optional(IrAnalyze *ira, IrInst *source_instr, ZigType *child_type,
16567 IrInstGen *optional, IrInstGen *non_optional, IrBinOp op_id)
16568{
16569 assert(optional->value->type->id == ZigTypeIdOptional);
16570 assert(optional->value->type->data.maybe.child_type == non_optional->value->type);
16571 assert(non_optional->value->type == child_type);
16572 assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
16573
16574 ZigType *result_type = ira->codegen->builtin_types.entry_bool;
16575 ir_append_basic_block_gen(&ira->new_irb, ira->new_irb.current_basic_block);
16576
16577 IrBasicBlockGen *null_block = ir_create_basic_block_gen(ira, source_instr->scope, "CmpOptionalNonOptionalOptionalNull");
16578 IrBasicBlockGen *non_null_block = ir_create_basic_block_gen(ira, source_instr->scope, "CmpOptionalNonOptionalOptionalNotNull");
16579 IrBasicBlockGen *end_block = ir_create_basic_block_gen(ira, source_instr->scope, "CmpOptionalNonOptionalEnd");
16580
16581 IrInstGen *is_non_null = ir_build_test_non_null_gen(ira, source_instr, optional);
16582 ir_build_cond_br_gen(ira, source_instr, is_non_null, non_null_block, null_block);
16583
16584 ir_set_cursor_at_end_and_append_block_gen(&ira->new_irb, non_null_block);
16585 IrInstGen *optional_unwrapped = ir_analyze_optional_value_payload_value(ira, source_instr, optional, false);
16586 if (type_is_invalid(optional_unwrapped->value->type)) {
16587 return ira->codegen->invalid_inst_gen;
16588 }
16589 IrInstGen *non_null_cmp_result = ir_build_bin_op_gen(ira, source_instr, result_type, op_id,
16590 optional_unwrapped, non_optional, false); // safety check unnecessary for comparison operators
16591 ir_build_br_gen(ira, source_instr, end_block);
16592
16593
16594 ir_set_cursor_at_end_and_append_block_gen(&ira->new_irb, null_block);
16595 IrInstGen *null_result = ir_const_bool(ira, source_instr, (op_id != IrBinOpCmpEq));
16596 ir_build_br_gen(ira, source_instr, end_block);
16597
16598 ir_set_cursor_at_end_gen(&ira->new_irb, end_block);
16599 int incoming_count = 2;
16600 IrBasicBlockGen **incoming_blocks = heap::c_allocator.allocate_nonzero<IrBasicBlockGen *>(incoming_count);
16601 incoming_blocks[0] = null_block;
16602 incoming_blocks[1] = non_null_block;
16603 IrInstGen **incoming_values = heap::c_allocator.allocate_nonzero<IrInstGen *>(incoming_count);
16604 incoming_values[0] = null_result;
16605 incoming_values[1] = non_null_cmp_result;
16606
16607 return ir_build_phi_gen(ira, source_instr, incoming_count, incoming_blocks, incoming_values, result_type);
16608}
16609
16610static IrInstGen *ir_analyze_cmp_optional_non_optional(IrAnalyze *ira, IrInst *source_instr,
16611 IrInstGen *op1, IrInstGen *op2, IrInstGen *optional, IrBinOp op_id)
16612{
16613 assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
16614 assert(optional->value->type->id == ZigTypeIdOptional);
16615 assert(get_src_ptr_type(optional->value->type) == nullptr);
16616
16617 IrInstGen *non_optional;
16618 if (op1 == optional) {
16619 non_optional = op2;
16620 } else if (op2 == optional) {
16621 non_optional = op1;
16622 } else {
16623 zig_unreachable();
16624 }
16625
16626 ZigType *child_type = optional->value->type->data.maybe.child_type;
16627 bool child_type_matches = (child_type == non_optional->value->type);
16628 if (!child_type_matches || !type_is_self_comparable(child_type, true)) {
16629 ErrorMsg *msg = ir_add_error_node(ira, source_instr->source_node, buf_sprintf("cannot compare types '%s' and '%s'",
16630 buf_ptr(&op1->value->type->name),
16631 buf_ptr(&op2->value->type->name)));
16632
16633 if (!child_type_matches) {
16634 if (non_optional->value->type->id == ZigTypeIdOptional) {
16635 add_error_note(ira->codegen, msg, source_instr->source_node, buf_sprintf(
16636 "optional to optional comparison is only supported for optional pointer types"));
16637 } else {
16638 add_error_note(ira->codegen, msg, source_instr->source_node,
16639 buf_sprintf("optional child type '%s' must be the same as non-optional type '%s'",
16640 buf_ptr(&child_type->name),
16641 buf_ptr(&non_optional->value->type->name)));
16642 }
16643 } else {
16644 add_error_note(ira->codegen, msg, source_instr->source_node,
16645 buf_sprintf("operator not supported for type '%s'",
16646 buf_ptr(&child_type->name)));
16647 }
16648 return ira->codegen->invalid_inst_gen;
16649 }
16650
16651 if (child_type->id == ZigTypeIdVector) {
16652 ir_add_error_node(ira, source_instr->source_node, buf_sprintf("TODO add comparison of optional vector"));
16653 return ira->codegen->invalid_inst_gen;
16654 }
16655
16656 if (IrInstGen *const_result = ir_try_evaluate_cmp_optional_non_optional_const(ira, source_instr, child_type,
16657 optional, non_optional, op_id))
16658 {
16659 return const_result;
16660 }
16661
16662 return ir_evaluate_cmp_optional_non_optional(ira, source_instr, child_type, optional, non_optional, op_id);
16663}
16664
1642816665static IrInstGen *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstSrcBinOp *bin_op_instruction) {
1642916666 IrInstGen *op1 = bin_op_instruction->op1->child;
1643016667 if (type_is_invalid(op1->value->type))
......@@ -16501,6 +16738,14 @@ static IrInstGen *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstSrcBinOp *bin_op_i
1650116738 } else {
1650216739 return is_non_null;
1650316740 }
16741 } else if (is_equality_cmp &&
16742 (op1->value->type->id == ZigTypeIdOptional && get_src_ptr_type(op1->value->type) == nullptr))
16743 {
16744 return ir_analyze_cmp_optional_non_optional(ira, &bin_op_instruction->base.base, op1, op2, op1, op_id);
16745 } else if(is_equality_cmp &&
16746 (op2->value->type->id == ZigTypeIdOptional && get_src_ptr_type(op2->value->type) == nullptr))
16747 {
16748 return ir_analyze_cmp_optional_non_optional(ira, &bin_op_instruction->base.base, op1, op2, op2, op_id);
1650416749 } else if (op1->value->type->id == ZigTypeIdNull || op2->value->type->id == ZigTypeIdNull) {
1650516750 ZigType *non_null_type = (op1->value->type->id == ZigTypeIdNull) ? op2->value->type : op1->value->type;
1650616751 ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null",
......@@ -16642,51 +16887,8 @@ static IrInstGen *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstSrcBinOp *bin_op_i
1664216887 if (type_is_invalid(resolved_type))
1664316888 return ira->codegen->invalid_inst_gen;
1664416889
16645 bool operator_allowed;
16646 switch (resolved_type->id) {
16647 case ZigTypeIdInvalid:
16648 zig_unreachable(); // handled above
16649
16650 case ZigTypeIdComptimeFloat:
16651 case ZigTypeIdComptimeInt:
16652 case ZigTypeIdInt:
16653 case ZigTypeIdFloat:
16654 zig_unreachable(); // handled with the type_is_numeric checks above
16655
16656 case ZigTypeIdVector:
16657 // Not every case is handled by the type_is_numeric checks above,
16658 // vectors of bool trigger this code path
16659 case ZigTypeIdBool:
16660 case ZigTypeIdMetaType:
16661 case ZigTypeIdVoid:
16662 case ZigTypeIdErrorSet:
16663 case ZigTypeIdFn:
16664 case ZigTypeIdOpaque:
16665 case ZigTypeIdBoundFn:
16666 case ZigTypeIdEnum:
16667 case ZigTypeIdEnumLiteral:
16668 case ZigTypeIdAnyFrame:
16669 operator_allowed = is_equality_cmp;
16670 break;
16671
16672 case ZigTypeIdPointer:
16673 operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC);
16674 break;
16890 bool operator_allowed = type_is_self_comparable(resolved_type, is_equality_cmp);
1667516891
16676 case ZigTypeIdUnreachable:
16677 case ZigTypeIdArray:
16678 case ZigTypeIdStruct:
16679 case ZigTypeIdUndefined:
16680 case ZigTypeIdNull:
16681 case ZigTypeIdErrorUnion:
16682 case ZigTypeIdUnion:
16683 case ZigTypeIdFnFrame:
16684 operator_allowed = false;
16685 break;
16686 case ZigTypeIdOptional:
16687 operator_allowed = is_equality_cmp && get_src_ptr_type(resolved_type) != nullptr;
16688 break;
16689 }
1669016892 if (!operator_allowed) {
1669116893 ir_add_error_node(ira, source_node,
1669216894 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
......@@ -16701,41 +16903,10 @@ static IrInstGen *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstSrcBinOp *bin_op_i
1670116903 if (type_is_invalid(casted_op2->value->type))
1670216904 return ira->codegen->invalid_inst_gen;
1670316905
16704 bool one_possible_value;
16705 switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
16706 case OnePossibleValueInvalid:
16707 return ira->codegen->invalid_inst_gen;
16708 case OnePossibleValueYes:
16709 one_possible_value = true;
16710 break;
16711 case OnePossibleValueNo:
16712 one_possible_value = false;
16713 break;
16714 }
16715
16716 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
16717 ZigValue *op1_val = one_possible_value ? casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
16718 if (op1_val == nullptr)
16719 return ira->codegen->invalid_inst_gen;
16720 ZigValue *op2_val = one_possible_value ? casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);
16721 if (op2_val == nullptr)
16722 return ira->codegen->invalid_inst_gen;
16723 if (resolved_type->id != ZigTypeIdVector)
16724 return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, bin_op_instruction, op_id, one_possible_value);
16725 IrInstGen *result = ir_const(ira, &bin_op_instruction->base.base,
16726 get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool));
16727 result->value->data.x_array.data.s_none.elements =
16728 ira->codegen->pass1_arena->allocate<ZigValue>(resolved_type->data.vector.len);
16729
16730 expand_undef_array(ira->codegen, result->value);
16731 for (size_t i = 0;i < resolved_type->data.vector.len;i++) {
16732 IrInstGen *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type,
16733 &op1_val->data.x_array.data.s_none.elements[i],
16734 &op2_val->data.x_array.data.s_none.elements[i],
16735 bin_op_instruction, op_id, one_possible_value);
16736 copy_const_val(ira->codegen, &result->value->data.x_array.data.s_none.elements[i], cur_res->value);
16737 }
16738 return result;
16906 IrInstGen *resolve_const_result = ir_try_evaluate_bin_op_cmp_const(ira, &bin_op_instruction->base.base, casted_op1,
16907 casted_op2, resolved_type, op_id);
16908 if (resolve_const_result != nullptr) {
16909 return resolve_const_result;
1673916910 }
1674016911
1674116912 ZigType *res_type = (resolved_type->id == ZigTypeIdVector) ?
test/compile_errors.zig+34
......@@ -7461,4 +7461,38 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
74617461 };
74627462 break :x tc;
74637463 });
7464
7465 cases.add("compare optional to non-optional with invalid types",
7466 \\export fn inconsistentChildType() void {
7467 \\ var x: ?i32 = undefined;
7468 \\ const y: comptime_int = 10;
7469 \\ _ = (x == y);
7470 \\}
7471 \\
7472 \\export fn optionalToOptional() void {
7473 \\ var x: ?i32 = undefined;
7474 \\ var y: ?i32 = undefined;
7475 \\ _ = (x == y);
7476 \\}
7477 \\
7478 \\export fn optionalVector() void {
7479 \\ var x: ?@Vector(10, i32) = undefined;
7480 \\ var y: @Vector(10, i32) = undefined;
7481 \\ _ = (x == y);
7482 \\}
7483 \\
7484 \\export fn invalidChildType() void {
7485 \\ var x: ?[3]i32 = undefined;
7486 \\ var y: [3]i32 = undefined;
7487 \\ _ = (x == y);
7488 \\}
7489 , &[_][]const u8{
7490 ":4:12: error: cannot compare types '?i32' and 'comptime_int'",
7491 ":4:12: note: optional child type 'i32' must be the same as non-optional type 'comptime_int'",
7492 ":10:12: error: cannot compare types '?i32' and '?i32'",
7493 ":10:12: note: optional to optional comparison is only supported for optional pointer types",
7494 ":16:12: error: TODO add comparison of optional vector",
7495 ":22:12: error: cannot compare types '?[3]i32' and '[3]i32'",
7496 ":22:12: note: operator not supported for type '[3]i32'",
7497 });
74647498}
test/stage1/behavior/optional.zig+22
......@@ -49,6 +49,28 @@ test "address of unwrap optional" {
4949 expect(foo.a == 1234);
5050}
5151
52test "equality compare optional with non-optional" {
53 test_cmp_optional_non_optional();
54 comptime test_cmp_optional_non_optional();
55}
56
57fn test_cmp_optional_non_optional() void {
58 var ten: i32 = 10;
59 var opt_ten: ?i32 = 10;
60 var five: i32 = 5;
61 var int_n: ?i32 = null;
62
63 expect(int_n != ten);
64 expect(opt_ten == ten);
65 expect(opt_ten != five);
66
67 // test evaluation is always lexical
68 // ensure that the optional isn't always computed before the non-optional
69 var mutable_state: i32 = 0;
70 _ = blk1: { mutable_state += 1; break :blk1 @as(?f64, 10.0); } != blk2: { expect(mutable_state == 1); break :blk2 @as(f64, 5.0); };
71 _ = blk1: { mutable_state += 1; break :blk1 @as(f64, 10.0); } != blk2: { expect(mutable_state == 2); break :blk2 @as(?f64, 5.0); };
72}
73
5274test "passing an optional integer as a parameter" {
5375 const S = struct {
5476 fn entry() bool {