authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-09 16:17:45-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-09-09 16:17:45-04:00
loga3993465feefae6e64f16ce7e7a70251a739cb22
treeb401f8096bc820007771045f0ef00b9c18d457da
parentfec795cd29909f0e43ba9de303b93309db8858b5
parent4b1cd45472cab5569438fef018990fbe8043c6c3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3200 from LemonBoy/eq-tagged-union

Allow comparison between union tag and enum literal

2 files changed, 55 insertions(+), 0 deletions(-)

src/ir.cpp+40
...@@ -13228,6 +13228,46 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13228,6 +13228,46 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13228 ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null",13228 ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null",
13229 buf_ptr(&non_null_type->name)));13229 buf_ptr(&non_null_type->name)));
13230 return ira->codegen->invalid_instruction;13230 return ira->codegen->invalid_instruction;
13231 } else if (is_equality_cmp && (
13232 (op1->value.type->id == ZigTypeIdEnumLiteral && op2->value.type->id == ZigTypeIdUnion) ||
13233 (op2->value.type->id == ZigTypeIdEnumLiteral && op1->value.type->id == ZigTypeIdUnion)))
13234 {
13235 // Support equality comparison between a union's tag value and a enum literal
13236 IrInstruction *union_val = op1->value.type->id == ZigTypeIdUnion ? op1 : op2;
13237 IrInstruction *enum_val = op1->value.type->id == ZigTypeIdUnion ? op2 : op1;
13238
13239 ZigType *tag_type = union_val->value.type->data.unionation.tag_type;
13240 assert(tag_type != nullptr);
13241
13242 IrInstruction *casted_union = ir_implicit_cast(ira, union_val, tag_type);
13243 if (type_is_invalid(casted_union->value.type))
13244 return ira->codegen->invalid_instruction;
13245
13246 IrInstruction *casted_val = ir_implicit_cast(ira, enum_val, tag_type);
13247 if (type_is_invalid(casted_val->value.type))
13248 return ira->codegen->invalid_instruction;
13249
13250 if (instr_is_comptime(casted_union)) {
13251 ConstExprValue *const_union_val = ir_resolve_const(ira, casted_union, UndefBad);
13252 if (!const_union_val)
13253 return ira->codegen->invalid_instruction;
13254
13255 ConstExprValue *const_enum_val = ir_resolve_const(ira, casted_val, UndefBad);
13256 if (!const_enum_val)
13257 return ira->codegen->invalid_instruction;
13258
13259 Cmp cmp_result = bigint_cmp(&const_union_val->data.x_union.tag, &const_enum_val->data.x_enum_tag);
13260 bool bool_result = (op_id == IrBinOpCmpEq) ? cmp_result == CmpEQ : cmp_result != CmpEQ;
13261
13262 return ir_const_bool(ira, &bin_op_instruction->base, bool_result);
13263 }
13264
13265 IrInstruction *result = ir_build_bin_op(&ira->new_irb,
13266 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
13267 op_id, casted_union, casted_val, bin_op_instruction->safety_check_on);
13268 result->value.type = ira->codegen->builtin_types.entry_bool;
13269
13270 return result;
13231 }13271 }
1323213272
13233 if (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) {13273 if (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) {
test/stage1/behavior/union.zig+15
...@@ -467,3 +467,18 @@ test "union no tag with struct member" {...@@ -467,3 +467,18 @@ test "union no tag with struct member" {
467 var u = Union{ .s = Struct{} };467 var u = Union{ .s = Struct{} };
468 u.foo();468 u.foo();
469}469}
470
471fn testComparison() void {
472 var x = Payload{.A = 42};
473 expect(x == .A);
474 expect(x != .B);
475 expect(x != .C);
476 expect((x == .B) == false);
477 expect((x == .C) == false);
478 expect((x != .A) == false);
479}
480
481test "comparison between union and enum literal" {
482 testComparison();
483 comptime testComparison();
484}