Commit cc63760587

LemonBoy <thatlemon@gmail.com>
2019-09-09 18:51:13
Allow comparison between union tag and enum literal
Closes #2810
1 parent 2482bdf
Changed files (2)
src
test
stage1
behavior
src/ir.cpp
@@ -13228,6 +13228,31 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
         ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null",
             buf_ptr(&non_null_type->name)));
         return ira->codegen->invalid_instruction;
+    } else if (is_equality_cmp && (
+        (op1->value.type->id == ZigTypeIdEnumLiteral && op2->value.type->id == ZigTypeIdUnion) ||
+        (op2->value.type->id == ZigTypeIdEnumLiteral && op1->value.type->id == ZigTypeIdUnion)))
+    {
+        // Support equality comparison between a union's tag value and a enum literal
+        IrInstruction *union_val = op1->value.type->id == ZigTypeIdUnion ? op1 : op2;
+        IrInstruction *enum_val = op1->value.type->id == ZigTypeIdUnion ? op2 : op1;
+
+        ZigType *tag_type = union_val->value.type->data.unionation.tag_type;
+        assert(tag_type != nullptr);
+
+        IrInstruction *casted_union = ir_implicit_cast(ira, union_val, tag_type);
+        if (type_is_invalid(casted_union->value.type))
+            return ira->codegen->invalid_instruction;
+
+        IrInstruction *casted_val = ir_implicit_cast(ira, enum_val, tag_type);
+        if (type_is_invalid(casted_val->value.type))
+            return ira->codegen->invalid_instruction;
+
+        IrInstruction *result = ir_build_bin_op(&ira->new_irb,
+            bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
+            op_id, casted_union, casted_val, bin_op_instruction->safety_check_on);
+        result->value.type = ira->codegen->builtin_types.entry_bool;
+
+        return result;
     }
 
     if (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) {
test/stage1/behavior/union.zig
@@ -467,3 +467,13 @@ test "union no tag with struct member" {
     var u = Union{ .s = Struct{} };
     u.foo();
 }
+
+test "comparison between union and enum literal" {
+    var x = Payload{.A = 42};
+    expect(x == .A);
+    expect(x != .B);
+    expect(x != .C);
+    expect((x == .B) == false);
+    expect((x == .C) == false);
+    expect((x != .A) == false);
+}