Skip to content

Commit 2651ad2

Browse files
committed
Also support optional bytes values
1 parent 6a37f6e commit 2651ad2

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

mypyc/irbuild/ll_builder.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,20 +2522,19 @@ def translate_eq_cmp(self, lreg: Value, rreg: Value, expr_op: str, line: int) ->
25222522

25232523
lopt = optional_value_type(ltype)
25242524
ropt = optional_value_type(rtype)
2525+
2526+
# Can we do a quick comparison of two optional types (special case None values)?
25252527
fast_opt_eq = False
2526-
if lopt is not None and ropt is not None:
2527-
# Can we do a quick comparison of two optional types?
2528-
if is_same_type(lopt, ropt) and is_str_rprimitive(lopt):
2528+
if lopt is not None:
2529+
if ropt is not None and is_same_type(lopt, ropt) and self._never_equal_to_none(lopt):
25292530
fast_opt_eq = True
2530-
elif lopt is not None:
2531-
if is_same_type(lopt, rtype) and is_str_rprimitive(lopt):
2531+
if is_same_type(lopt, rtype) and self._never_equal_to_none(lopt):
25322532
fast_opt_eq = True
25332533
elif ropt is not None:
2534-
if is_same_type(ropt, ltype) and is_str_rprimitive(ropt):
2534+
if is_same_type(ropt, ltype) and self._never_equal_to_none(ropt):
25352535
fast_opt_eq = True
2536-
25372536
if fast_opt_eq:
2538-
return self.translate_fast_optional_eq_cmp(lreg, rreg, expr_op, line)
2537+
return self._translate_fast_optional_eq_cmp(lreg, rreg, expr_op, line)
25392538

25402539
if not (isinstance(ltype, RInstance) and ltype == rtype):
25412540
return None
@@ -2563,11 +2562,18 @@ def translate_eq_cmp(self, lreg: Value, rreg: Value, expr_op: str, line: int) ->
25632562

25642563
return self.gen_method_call(lreg, op_methods[expr_op], [rreg], ltype, line)
25652564

2566-
def translate_fast_optional_eq_cmp(
2565+
def _never_equal_to_none(self, typ: RType) -> bool:
2566+
"""Are the values of type never equal to None?"""
2567+
# TODO: Support RInstance with no custom __eq__/__ne__ and other primitive types.
2568+
return is_str_rprimitive(typ) or is_bytes_rprimitive(typ)
2569+
2570+
def _translate_fast_optional_eq_cmp(
25672571
self, lreg: Value, rreg: Value, expr_op: str, line: int
25682572
) -> Value:
25692573
if not isinstance(lreg.type, RUnion):
25702574
lreg, rreg = rreg, lreg
2575+
value_typ = optional_value_type(lreg.type)
2576+
assert value_typ
25712577
res = Register(bool_rprimitive)
25722578
x = self.add(ComparisonOp(lreg, self.none_object(), ComparisonOp.EQ, line))
25732579
l_none = BasicBlock()
@@ -2584,12 +2590,13 @@ def translate_fast_optional_eq_cmp(
25842590
self.goto(out)
25852591
self.activate_block(l_not_none)
25862592
if not isinstance(rreg.type, RUnion):
2587-
z = self.compare_strings(
2588-
self.unbox_or_cast(lreg, str_rprimitive, line, can_borrow=True, unchecked=True),
2593+
z = self.translate_eq_cmp(
2594+
self.unbox_or_cast(lreg, value_typ, line, can_borrow=True, unchecked=True),
25892595
rreg,
25902596
expr_op,
25912597
line,
25922598
)
2599+
assert z is not None
25932600
self.add(Assign(res, z))
25942601
else:
25952602
r_none = BasicBlock()
@@ -2600,12 +2607,13 @@ def translate_fast_optional_eq_cmp(
26002607
self.add(Assign(res, self.false()))
26012608
self.goto(out)
26022609
self.activate_block(r_not_none)
2603-
z = self.compare_strings(
2604-
self.unbox_or_cast(lreg, str_rprimitive, line, can_borrow=True, unchecked=True),
2605-
self.unbox_or_cast(rreg, str_rprimitive, line, can_borrow=True, unchecked=True),
2610+
z = self.translate_eq_cmp(
2611+
self.unbox_or_cast(lreg, value_typ, line, can_borrow=True, unchecked=True),
2612+
self.unbox_or_cast(rreg, value_typ, line, can_borrow=True, unchecked=True),
26062613
expr_op,
26072614
line,
26082615
)
2616+
assert z is not None
26092617
self.add(Assign(res, z))
26102618
self.goto(out)
26112619
self.activate_block(out)

mypyc/test-data/irbuild-str.test

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -741,20 +741,21 @@ L3:
741741
keep_alive x
742742
return r2
743743

744-
[case testOptionalStrEquality3]
744+
[case testOptionalBytesEquality]
745745
from typing import Optional
746746

747-
def non_opt_opt(x: str, y: Optional[str]) -> bool:
747+
def non_opt_opt(x: bytes, y: Optional[bytes]) -> bool:
748748
return x == y
749749
[out]
750750
def non_opt_opt(x, y):
751-
x :: str
752-
y :: union[str, None]
751+
x :: bytes
752+
y :: union[bytes, None]
753753
r0 :: object
754754
r1 :: bit
755755
r2 :: bool
756-
r3 :: str
757-
r4 :: bool
756+
r3 :: bytes
757+
r4 :: i32
758+
r5, r6 :: bit
758759
L0:
759760
r0 = load_address _Py_NoneStruct
760761
r1 = y == r0
@@ -763,9 +764,11 @@ L1:
763764
r2 = 0
764765
goto L3
765766
L2:
766-
r3 = unchecked borrow cast(str, y)
767-
r4 = CPyStr_Equal(r3, x)
768-
r2 = r4
767+
r3 = unchecked borrow cast(bytes, y)
768+
r4 = CPyBytes_Compare(r3, x)
769+
r5 = r4 >= 0 :: signed
770+
r6 = r4 == 1
771+
r2 = r6
769772
L3:
770773
keep_alive y
771774
return r2

0 commit comments

Comments
 (0)