Skip to content

Commit db9d9cb

Browse files
committed
Fix QPY serialization.
We need to reject types with const=True in QPY until it supports them. For now, I've also made the Index and shift operator constructors lift their RHS to the same const-ness as the target to make it less likely that existing users of expr run into issues when serializing to older QPY versions.
1 parent 9f8313c commit db9d9cb

File tree

3 files changed

+18
-12
lines changed

3 files changed

+18
-12
lines changed

qiskit/circuit/classical/expr/constructors.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ def _shift_like(
543543
left = _coerce_lossless(left, type) if type is not None else left
544544
else:
545545
left = lift(left, type)
546-
right = lift(right)
546+
right = lift(right, try_const=left.type.const)
547547
if left.type.kind != types.Uint or right.type.kind != types.Uint:
548548
raise TypeError(f"invalid types for '{op}': '{left.type}' and '{right.type}'")
549549
return Binary(
@@ -616,7 +616,8 @@ def index(target: typing.Any, index: typing.Any, /) -> Expr:
616616
>>> expr.index(ClassicalRegister(8, "a"), 3)
617617
Index(Var(ClassicalRegister(8, "a"), Uint(8, const=False)), Value(3, Uint(2, const=True)), Bool(const=False))
618618
"""
619-
target, index = lift(target), lift(index)
619+
target = lift(target)
620+
index = lift(index, try_const=target.type.const)
620621
if target.type.kind is not types.Uint or index.type.kind is not types.Uint:
621622
raise TypeError(f"invalid types for indexing: '{target.type}' and '{index.type}'")
622623
return Index(target, index, types.Bool(const=target.type.const and index.type.const))

qiskit/qpy/binary_io/value.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,10 @@ def _write_expr(
367367

368368

369369
def _write_expr_type(file_obj, type_: types.Type):
370-
if type_.kind is types.Bool:
370+
# Currently, QPY doesn't support const types
371+
if type_.kind is types.Bool and not type_.const:
371372
file_obj.write(type_keys.ExprType.BOOL)
372-
elif type_.kind is types.Uint:
373+
elif type_.kind is types.Uint and not type_.const:
373374
file_obj.write(type_keys.ExprType.UINT)
374375
file_obj.write(
375376
struct.pack(formats.EXPR_TYPE_UINT_PACK, *formats.EXPR_TYPE_UINT(type_.width))

test/python/circuit/classical/test_expr_constructors.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -529,9 +529,7 @@ def test_index_explicit(self):
529529

530530
self.assertEqual(
531531
expr.index(cr, 3),
532-
expr.Index(
533-
expr.Var(cr, types.Uint(4)), expr.Value(3, types.Uint(2, const=True)), types.Bool()
534-
),
532+
expr.Index(expr.Var(cr, types.Uint(4)), expr.Value(3, types.Uint(2)), types.Bool()),
535533
)
536534
self.assertEqual(
537535
expr.index(a, cr),
@@ -557,23 +555,29 @@ def test_shift_explicit(self, function, opcode):
557555
expr.Binary(
558556
opcode,
559557
expr.Var(cr, types.Uint(8)),
560-
expr.Value(5, types.Uint(3, const=True)),
558+
expr.Value(5, types.Uint(3)),
561559
types.Uint(8),
562560
),
563561
)
564562
self.assertEqual(
565563
function(a, cr),
566564
expr.Binary(opcode, a, expr.Var(cr, types.Uint(8)), types.Uint(4)),
567565
)
568-
# TODO: as it is, the LHS of a shift expression always becomes exactly the explicit
569-
# type passed to `shift_*`. The RHS is inferred with lift, and stays const if it's
570-
# const. Is this the best behavior?
566+
self.assertEqual(
567+
function(3, 5),
568+
expr.Binary(
569+
opcode,
570+
expr.Value(3, types.Uint(2, const=True)),
571+
expr.Value(5, types.Uint(3, const=True)),
572+
types.Uint(2, const=True),
573+
),
574+
)
571575
self.assertEqual(
572576
function(3, 5, types.Uint(8)),
573577
expr.Binary(
574578
opcode,
575579
expr.Value(3, types.Uint(8)),
576-
expr.Value(5, types.Uint(3, const=True)),
580+
expr.Value(5, types.Uint(3)),
577581
types.Uint(8),
578582
),
579583
)

0 commit comments

Comments
 (0)