authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-16 16:39:31-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-16 16:39:31-05:00
log0caee421e38672869dd596e6af732567cfaf2037
tree44ccd0e37f9f4b6d3ed984ed5bd20f7326dab79a
parent867686af420bab965f63359499a526f35e875c9a

ability to equality compare with null

closes #106

2 files changed, 66 insertions(+), 11 deletions(-)

src/ir.cpp+52-10
......@@ -1225,7 +1225,7 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *so
12251225 return &instruction->base;
12261226}
12271227
1228static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1228static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
12291229 IrInstructionTestNonNull *instruction = ir_build_instruction<IrInstructionTestNonNull>(irb, scope, source_node);
12301230 instruction->value = value;
12311231
......@@ -1234,10 +1234,10 @@ static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *
12341234 return &instruction->base;
12351235}
12361236
1237static IrInstruction *ir_build_test_null_from(IrBuilder *irb, IrInstruction *old_instruction,
1237static IrInstruction *ir_build_test_nonnull_from(IrBuilder *irb, IrInstruction *old_instruction,
12381238 IrInstruction *value)
12391239{
1240 IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->scope,
1240 IrInstruction *new_instruction = ir_build_test_nonnull(irb, old_instruction->scope,
12411241 old_instruction->source_node, value);
12421242 ir_link_new_instruction(new_instruction, old_instruction);
12431243 return new_instruction;
......@@ -2923,7 +2923,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29232923 IrBasicBlock *null_block = ir_build_basic_block(irb, scope, "MaybeRetNull");
29242924 IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "MaybeRetOk");
29252925
2926 IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, return_value);
2926 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, return_value);
29272927
29282928 IrInstruction *is_comptime;
29292929 if (ir_should_inline(irb)) {
......@@ -2980,7 +2980,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29802980 if (maybe_val_ptr == irb->codegen->invalid_instruction)
29812981 return irb->codegen->invalid_instruction;
29822982 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
2983 IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, maybe_val);
2983 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
29842984
29852985 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn");
29862986 IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue");
......@@ -3293,7 +3293,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
32933293 return irb->codegen->invalid_instruction;
32943294
32953295 IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);
3296 IrInstruction *is_non_null = ir_build_test_null(irb, parent_scope, node, maybe_val);
3296 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val);
32973297
32983298 IrInstruction *is_comptime;
32993299 if (ir_should_inline(irb)) {
......@@ -4595,7 +4595,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
45954595 return maybe_val_ptr;
45964596
45974597 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
4598 IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, maybe_val);
4598 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
45994599
46004600 IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen");
46014601 IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse");
......@@ -6839,13 +6839,55 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
68396839static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
68406840 IrInstruction *op1 = bin_op_instruction->op1->other;
68416841 IrInstruction *op2 = bin_op_instruction->op2->other;
6842
6843 IrBinOp op_id = bin_op_instruction->op_id;
6844 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
6845 if (is_equality_cmp &&
6846 ((op1->value.type->id == TypeTableEntryIdNullLit && op2->value.type->id == TypeTableEntryIdMaybe) ||
6847 (op2->value.type->id == TypeTableEntryIdNullLit && op1->value.type->id == TypeTableEntryIdMaybe) ||
6848 (op1->value.type->id == TypeTableEntryIdNullLit && op2->value.type->id == TypeTableEntryIdNullLit)))
6849 {
6850 bool depends_on_compile_var = op1->value.depends_on_compile_var || op2->value.depends_on_compile_var;
6851 if (op1->value.type->id == TypeTableEntryIdNullLit && op2->value.type->id == TypeTableEntryIdNullLit) {
6852 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base, depends_on_compile_var);
6853 out_val->data.x_bool = (op_id == IrBinOpCmpEq);
6854 return ira->codegen->builtin_types.entry_bool;
6855 }
6856 IrInstruction *maybe_op;
6857 if (op1->value.type->id == TypeTableEntryIdNullLit) {
6858 maybe_op = op2;
6859 } else if (op2->value.type->id == TypeTableEntryIdNullLit) {
6860 maybe_op = op1;
6861 } else {
6862 zig_unreachable();
6863 }
6864 if (instr_is_comptime(maybe_op)) {
6865 ConstExprValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad);
6866 if (!maybe_val)
6867 return ira->codegen->builtin_types.entry_invalid;
6868 bool is_null = (maybe_val->data.x_maybe == nullptr);
6869 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base, depends_on_compile_var);
6870 out_val->data.x_bool = (op_id == IrBinOpCmpEq) ? is_null : !is_null;
6871 return ira->codegen->builtin_types.entry_bool;
6872 }
6873
6874 IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope,
6875 bin_op_instruction->base.source_node, maybe_op);
6876 is_non_null->value.type = ira->codegen->builtin_types.entry_bool;
6877
6878 if (op_id == IrBinOpCmpEq) {
6879 ir_build_bool_not_from(&ira->new_irb, &bin_op_instruction->base, is_non_null);
6880 } else {
6881 ir_link_new_instruction(is_non_null, &bin_op_instruction->base);
6882 }
6883 return ira->codegen->builtin_types.entry_bool;
6884 }
6885
68426886 IrInstruction *instructions[] = {op1, op2};
68436887 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
68446888 if (resolved_type->id == TypeTableEntryIdInvalid)
68456889 return resolved_type;
6846 IrBinOp op_id = bin_op_instruction->op_id;
68476890
6848 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
68496891 AstNode *source_node = bin_op_instruction->base.source_node;
68506892 switch (resolved_type->id) {
68516893 case TypeTableEntryIdInvalid:
......@@ -9240,7 +9282,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn
92409282 return ira->codegen->builtin_types.entry_bool;
92419283 }
92429284
9243 ir_build_test_null_from(&ira->new_irb, &instruction->base, value);
9285 ir_build_test_nonnull_from(&ira->new_irb, &instruction->base, value);
92449286 return ira->codegen->builtin_types.entry_bool;
92459287 } else if (type_entry->id == TypeTableEntryIdNullLit) {
92469288 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
test/cases/null.zig+14-1
......@@ -83,8 +83,11 @@ const Particle = struct {
8383fn nullLiteralOutsideFunction() {
8484 @setFnTest(this);
8585
86 const is_null = if (const _ ?= here_is_a_null_literal.context) false else true;
86 const is_null = here_is_a_null_literal.context == null;
8787 assert(is_null);
88
89 const is_non_null = here_is_a_null_literal.context != null;
90 assert(!is_non_null);
8891}
8992const SillyStruct = struct {
9093 context: ?i32,
......@@ -99,3 +102,13 @@ fn foo(x: ?i32) -> ?bool {
99102 const value = ?return x;
100103 return value > 1234;
101104}
105
106fn testNullRuntime() {
107 @setFnTest(this);
108
109 testTestNullRuntime(null);
110}
111fn testTestNullRuntime(x: ?i32) {
112 assert(x == null);
113 assert(!(x != null));
114}