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...@@ -1225,7 +1225,7 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *so
1225 return &instruction->base;1225 return &instruction->base;
1226}1226}
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) {
1229 IrInstructionTestNonNull *instruction = ir_build_instruction<IrInstructionTestNonNull>(irb, scope, source_node);1229 IrInstructionTestNonNull *instruction = ir_build_instruction<IrInstructionTestNonNull>(irb, scope, source_node);
1230 instruction->value = value;1230 instruction->value = value;
12311231
...@@ -1234,10 +1234,10 @@ static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *...@@ -1234,10 +1234,10 @@ static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *
1234 return &instruction->base;1234 return &instruction->base;
1235}1235}
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,
1238 IrInstruction *value)1238 IrInstruction *value)
1239{1239{
1240 IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->scope,1240 IrInstruction *new_instruction = ir_build_test_nonnull(irb, old_instruction->scope,
1241 old_instruction->source_node, value);1241 old_instruction->source_node, value);
1242 ir_link_new_instruction(new_instruction, old_instruction);1242 ir_link_new_instruction(new_instruction, old_instruction);
1243 return new_instruction;1243 return new_instruction;
...@@ -2923,7 +2923,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2923,7 +2923,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2923 IrBasicBlock *null_block = ir_build_basic_block(irb, scope, "MaybeRetNull");2923 IrBasicBlock *null_block = ir_build_basic_block(irb, scope, "MaybeRetNull");
2924 IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "MaybeRetOk");2924 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
2928 IrInstruction *is_comptime;2928 IrInstruction *is_comptime;
2929 if (ir_should_inline(irb)) {2929 if (ir_should_inline(irb)) {
...@@ -2980,7 +2980,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2980,7 +2980,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2980 if (maybe_val_ptr == irb->codegen->invalid_instruction)2980 if (maybe_val_ptr == irb->codegen->invalid_instruction)
2981 return irb->codegen->invalid_instruction;2981 return irb->codegen->invalid_instruction;
2982 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);2982 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
2985 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn");2985 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn");
2986 IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue");2986 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...@@ -3293,7 +3293,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
3293 return irb->codegen->invalid_instruction;3293 return irb->codegen->invalid_instruction;
32943294
3295 IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);3295 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
3298 IrInstruction *is_comptime;3298 IrInstruction *is_comptime;
3299 if (ir_should_inline(irb)) {3299 if (ir_should_inline(irb)) {
...@@ -4595,7 +4595,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4595,7 +4595,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
4595 return maybe_val_ptr;4595 return maybe_val_ptr;
45964596
4597 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);4597 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
4600 IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen");4600 IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen");
4601 IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse");4601 IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse");
...@@ -6839,13 +6839,55 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp...@@ -6839,13 +6839,55 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
6839static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {6839static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
6840 IrInstruction *op1 = bin_op_instruction->op1->other;6840 IrInstruction *op1 = bin_op_instruction->op1->other;
6841 IrInstruction *op2 = bin_op_instruction->op2->other;6841 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
6842 IrInstruction *instructions[] = {op1, op2};6886 IrInstruction *instructions[] = {op1, op2};
6843 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);6887 TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
6844 if (resolved_type->id == TypeTableEntryIdInvalid)6888 if (resolved_type->id == TypeTableEntryIdInvalid)
6845 return resolved_type;6889 return resolved_type;
6846 IrBinOp op_id = bin_op_instruction->op_id;
68476890
6848 bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
6849 AstNode *source_node = bin_op_instruction->base.source_node;6891 AstNode *source_node = bin_op_instruction->base.source_node;
6850 switch (resolved_type->id) {6892 switch (resolved_type->id) {
6851 case TypeTableEntryIdInvalid:6893 case TypeTableEntryIdInvalid:
...@@ -9240,7 +9282,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn...@@ -9240,7 +9282,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn
9240 return ira->codegen->builtin_types.entry_bool;9282 return ira->codegen->builtin_types.entry_bool;
9241 }9283 }
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);
9244 return ira->codegen->builtin_types.entry_bool;9286 return ira->codegen->builtin_types.entry_bool;
9245 } else if (type_entry->id == TypeTableEntryIdNullLit) {9287 } else if (type_entry->id == TypeTableEntryIdNullLit) {
9246 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);9288 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
test/cases/null.zig+14-1
...@@ -83,8 +83,11 @@ const Particle = struct {...@@ -83,8 +83,11 @@ const Particle = struct {
83fn nullLiteralOutsideFunction() {83fn nullLiteralOutsideFunction() {
84 @setFnTest(this);84 @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;
87 assert(is_null);87 assert(is_null);
88
89 const is_non_null = here_is_a_null_literal.context != null;
90 assert(!is_non_null);
88}91}
89const SillyStruct = struct {92const SillyStruct = struct {
90 context: ?i32,93 context: ?i32,
...@@ -99,3 +102,13 @@ fn foo(x: ?i32) -> ?bool {...@@ -99,3 +102,13 @@ fn foo(x: ?i32) -> ?bool {
99 const value = ?return x;102 const value = ?return x;
100 return value > 1234;103 return value > 1234;
101}104}
105
106fn testNullRuntime() {
107 @setFnTest(this);
108
109 testTestNullRuntime(null);
110}
111fn testTestNullRuntime(x: ?i32) {
112 assert(x == null);
113 assert(!(x != null));
114}