diff --git a/Cargo.lock b/Cargo.lock index 32acde979305..c83ab9fd2e62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -737,12 +737,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - [[package]] name = "heapless" version = "0.8.0" @@ -767,12 +761,12 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "indexmap" -version = "2.12.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.15.5", "rayon", ] @@ -1096,9 +1090,9 @@ dependencies = [ [[package]] name = "numpy" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2dba356160b54f5371b550575b78130a54718b4c6e46b3f33a6da74a27e78b" +checksum = "0fa24ffc88cf9d43f7269d6b6a0d0a00010924a8cc90604a21ef9c433b66998d" dependencies = [ "libc", "nalgebra", @@ -1368,9 +1362,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" +checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf" dependencies = [ "hashbrown 0.15.5", "indexmap", @@ -1379,6 +1373,7 @@ dependencies = [ "memoffset", "num-bigint", "num-complex", + "num-traits", "once_cell", "portable-atomic", "pyo3-build-config", @@ -1390,18 +1385,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" +checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb" dependencies = [ "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" +checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be" dependencies = [ "libc", "pyo3-build-config", @@ -1409,9 +1404,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" +checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -1421,9 +1416,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" +checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index b1c783302796..aa30331f4c37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,11 +17,11 @@ license = "Apache-2.0" bytemuck = "1.24" bitfield-struct = "0.12.1" indexmap.version = "2.10.0" -hashbrown.version = "0.15.2" +hashbrown.version = "0.15.5" num-bigint = "0.4" num-complex = "0.4" nalgebra = "0.33" -numpy = "0.26" +numpy = "0.27" ndarray = "0.16" smallvec = "1.15" thiserror = "2.0" @@ -44,7 +44,7 @@ uuid = { version = "1.18", features = ["v4", "fast-rng"], default-features = fal # distributions). We only activate that feature when building the C extension module; we still need # it disabled for Rust-only tests to avoid linker errors with it not being loaded. See # https://pyo3.rs/main/features#extension-module for more. -pyo3 = { version = "0.26", features = ["abi3-py39"] } +pyo3 = { version = "0.27", features = ["abi3-py39"] } # These are our own crates. qiskit-accelerate = { path = "crates/accelerate" } diff --git a/crates/circuit/src/bit.rs b/crates/circuit/src/bit.rs index a25c6d101376..8bab35fc7d73 100644 --- a/crates/circuit/src/bit.rs +++ b/crates/circuit/src/bit.rs @@ -86,22 +86,28 @@ where self.index as usize, self.registers .into_pyobject(py)? - .downcast_into::()? + .cast_into::()? .unbind(), ) .into_pyobject(py) } } -impl<'py, R> FromPyObject<'py> for BitLocations +impl<'a, 'py, R> FromPyObject<'a, 'py> for BitLocations where - R: Debug + Clone + Register + for<'a> IntoPyObject<'a> + for<'a> FromPyObject<'a>, + R: Debug + + Clone + + Register + + IntoPyObject<'py> + + for<'b> FromPyObject<'b, 'py, Error: Into>, { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - let ob_down = ob.downcast::()?.borrow(); + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + let ob_down = ob.cast::()?.borrow(); Ok(Self { index: ob_down.index as u32, - registers: ob_down.registers.extract(ob.py())?, + registers: ob_down.registers.bind(ob.py()).extract()?, }) } } @@ -509,9 +515,11 @@ macro_rules! create_bit_object { } } - impl<'py> FromPyObject<'py> for $bit_struct { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - Ok(ob.downcast::<$pybit_struct>()?.borrow().0.clone()) + impl<'a, 'py> FromPyObject<'a, 'py> for $bit_struct { + type Error = ::pyo3::CastError<'a, 'py>; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + ob.cast::<$pybit_struct>().map(|ob| ob.borrow().0.clone()) } } // The owning impl of `IntoPyObject` needs to be done manually, to better handle @@ -629,9 +637,11 @@ macro_rules! create_bit_object { } } - impl<'py> FromPyObject<'py> for $reg_struct { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - Ok(ob.downcast::<$pyreg_struct>()?.borrow().0.clone()) + impl<'a, 'py> FromPyObject<'a, 'py> for $reg_struct { + type Error = ::pyo3::CastError<'a, 'py>; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + ob.cast::<$pyreg_struct>().map(|ob| ob.borrow().0.clone()) } } // The owning impl of `IntoPyObject` needs to be done manually, to better handle @@ -761,7 +771,7 @@ macro_rules! create_bit_object { Ok(PyList::new(ob.py(), s.into_iter().map(get_inner))?.into_any()) } } - } else if let Ok(list) = ob.downcast::() { + } else if let Ok(list) = ob.cast::() { let out = PyList::empty(ob.py()); for item in list.iter() { out.append(get_inner(PySequenceIndex::convert_idx( diff --git a/crates/circuit/src/bit_locator.rs b/crates/circuit/src/bit_locator.rs index b8cc5d880916..9a9279b7ecf8 100644 --- a/crates/circuit/src/bit_locator.rs +++ b/crates/circuit/src/bit_locator.rs @@ -102,8 +102,13 @@ where impl BitLocator where - B: Debug + Clone + Hash + Eq + for<'py> IntoPyObject<'py> + for<'py> FromPyObject<'py>, - R: Register + Debug + Clone + for<'py> IntoPyObject<'py> + for<'py> FromPyObject<'py>, + B: Debug + + Clone + + Hash + + Eq + + for<'py> IntoPyObject<'py> + + for<'a, 'py> FromPyObject<'a, 'py, Error: Into>, + R: Register + Debug + Clone + for<'py> IntoPyObject<'py> + for<'a, 'py> FromPyObject<'a, 'py>, { /// Get or create the cached Python dictionary that represents this. pub fn cached(&self, py: Python) -> &Py { @@ -121,7 +126,10 @@ where pub fn from_py_dict(dict: &Bound) -> PyResult { let mut locator = Self::new(); for (key, value) in dict { - locator.insert(key.extract()?, value.extract()?); + locator.insert( + key.extract().map_err(Into::::into)?, + value.extract()?, + ); } Ok(locator) } diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 2076b3194ba8..e0d5a4b0ab28 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -184,7 +184,7 @@ impl CircuitVarInfo { } fn from_pickle(ob: &Bound) -> PyResult { - let val_tuple = ob.downcast::()?; + let val_tuple = ob.cast::()?; Ok(CircuitVarInfo { var: Var(val_tuple.get_item(0)?.extract()?), type_: match val_tuple.get_item(1)?.extract::()? { @@ -232,7 +232,7 @@ impl CircuitStretchInfo { } fn from_pickle(ob: &Bound) -> PyResult { - let val_tuple = ob.downcast::()?; + let val_tuple = ob.cast::()?; Ok(CircuitStretchInfo { stretch: Stretch(val_tuple.get_item(0)?.extract()?), type_: match val_tuple.get_item(1)?.extract::()? { @@ -267,7 +267,7 @@ impl CircuitIdentifierInfo { } fn from_pickle(ob: &Bound) -> PyResult { - let val_tuple = ob.downcast::()?; + let val_tuple = ob.cast::()?; match val_tuple.get_item(0)?.extract::()? { 0 => Ok(CircuitIdentifierInfo::Stretch( CircuitStretchInfo::from_pickle(&val_tuple.get_item(1)?)?, @@ -1104,7 +1104,7 @@ impl CircuitData { fn set_single(slf: &mut CircuitData, index: usize, value: &Bound) -> PyResult<()> { let py = value.py(); slf.untrack_instruction_parameters(index)?; - slf.data[index] = slf.pack(py, &value.downcast::()?.borrow())?; + slf.data[index] = slf.pack(py, &value.cast::()?.borrow())?; slf.track_instruction_parameters(index)?; Ok(()) } @@ -1129,7 +1129,7 @@ impl CircuitData { })? } else { for value in values[indices.len()..].iter().rev() { - self.insert(stop as isize, value.downcast()?.borrow())?; + self.insert(stop as isize, value.cast()?.borrow())?; } } Ok(()) @@ -1225,7 +1225,7 @@ impl CircuitData { } pub fn extend(&mut self, itr: &Bound) -> PyResult<()> { - if let Ok(other) = itr.downcast::() { + if let Ok(other) = itr.cast::() { let other = other.borrow(); // Fast path to avoid unnecessary construction of CircuitInstruction instances. self.data.reserve(other.data.len()); @@ -1259,7 +1259,7 @@ impl CircuitData { return Ok(()); } for v in itr.try_iter()? { - self.append(v?.downcast()?)?; + self.append(v?.cast()?)?; } Ok(()) } @@ -1287,7 +1287,7 @@ impl CircuitData { } else { let values = sequence .try_iter()? - .map(|ob| Param::extract_no_coerce(&ob?)) + .map(|ob| Param::extract_no_coerce(ob?.as_borrowed())) .collect::>>()?; self.assign_parameters_from_slice(&values) } @@ -1345,7 +1345,7 @@ impl CircuitData { return Ok(false); } - if let Ok(other_cd) = other.downcast::() { + if let Ok(other_cd) = other.cast::() { if !slf .getattr("global_phase")? .eq(other_cd.getattr("global_phase")?)? @@ -2553,24 +2553,28 @@ impl CircuitData { // to a numeric quantity already, so the match here is // definitely parameterized. match &new_param { - Param::ParameterExpression(expr) => match expr - .try_to_value(true) - { - Ok(_) => { - // fully bound, validate parameters - Param::extract_no_coerce(&op.call_method1( - validate_parameter_attr, - (new_param,), - )?)? + Param::ParameterExpression(expr) => { + match expr.try_to_value(true) { + Ok(_) => { + // fully bound, validate parameters + Param::extract_no_coerce( + op.call_method1( + validate_parameter_attr, + (new_param,), + )? + .as_borrowed(), + )? + } + Err(_) => new_param, // not bound yet, cannot validate } - Err(_) => new_param, // not bound yet, cannot validate - }, - new_param => { - Param::extract_no_coerce(&op.call_method1( + } + new_param => Param::extract_no_coerce( + op.call_method1( validate_parameter_attr, (new_param,), - )?)? - } + )? + .as_borrowed(), + )?, } } Param::Obj(obj) => { @@ -2579,7 +2583,7 @@ impl CircuitData { return Err(inconsistent()); } Param::extract_no_coerce( - &obj.call_method( + obj.call_method( assign_parameters_attr, ([(symbol.clone(), value.as_ref())] .into_py_dict(py)?,), @@ -2587,7 +2591,8 @@ impl CircuitData { &[("inplace", false), ("flat_input", true)] .into_py_dict(py)?, ), - )?, + )? + .as_borrowed(), )? } }; @@ -2979,8 +2984,10 @@ impl CircuitData { /// PyO3-provided `FromPyObject` implementations on containers. #[repr(transparent)] struct AssignParam(Param); -impl<'py> FromPyObject<'py> for AssignParam { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for AssignParam { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { Ok(Self(Param::extract_no_coerce(ob)?)) } } @@ -3007,8 +3014,8 @@ fn bit_argument_conversion( bit_set: &BitLocator, ) -> PyResult> where - B: Debug + Clone + Hash + Eq + for<'py> FromPyObject<'py>, - R: Register + Debug + Clone + Hash + for<'py> FromPyObject<'py>, + B: Debug + Clone + Hash + Eq + for<'a, 'py> FromPyObject<'a, 'py>, + R: Register + Debug + Clone + Hash + for<'a, 'py> FromPyObject<'a, 'py>, { // The duplication between this function and `_bit_argument_conversion_scalar` is so that fast // paths return as quickly as possible, and all valid specifiers will resolve without needing to @@ -3052,7 +3059,7 @@ where }) .collect::>(); } - let err_message = if let Ok(bit) = specifier.downcast::() { + let err_message = if let Ok(bit) = specifier.cast::() { format!( "Incorrect bit type: expected '{}' but got '{}'", stringify!(B), @@ -3074,8 +3081,8 @@ fn bit_argument_conversion_scalar( bit_set: &BitLocator, ) -> PyResult where - B: Debug + Clone + Hash + Eq + for<'py> FromPyObject<'py>, - R: Register + Debug + Clone + Hash + for<'py> FromPyObject<'py>, + B: Debug + Clone + Hash + Eq + for<'a, 'py> FromPyObject<'a, 'py>, + R: Register + Debug + Clone + Hash + for<'a, 'py> FromPyObject<'a, 'py>, { if let Ok(bit) = specifier.extract() { if bit_set.contains_key(&bit) { @@ -3102,7 +3109,7 @@ where ))) } } else { - let err_message = if let Ok(bit) = specifier.downcast::() { + let err_message = if let Ok(bit) = specifier.cast::() { format!( "Incorrect bit type: expected '{}' but got '{}'", stringify!(B), diff --git a/crates/circuit/src/circuit_instruction.rs b/crates/circuit/src/circuit_instruction.rs index fdf71ab901d4..2e97f65a3f07 100644 --- a/crates/circuit/src/circuit_instruction.rs +++ b/crates/circuit/src/circuit_instruction.rs @@ -415,7 +415,7 @@ impl CircuitInstruction { if other.is_instance_of::() { return Ok(Some(self_._legacy_format(py)?.eq(other)?)); } - let Ok(other) = other.downcast::() else { + let Ok(other) = other.cast::() else { return Ok(None); }; let other = other.try_borrow()?; @@ -467,13 +467,15 @@ pub struct OperationFromPython { pub label: Option>, } -impl<'py> FromPyObject<'py> for OperationFromPython { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for OperationFromPython { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let py = ob.py(); let ob_type = ob .getattr(intern!(py, "base_class")) .ok() - .map(|base| base.downcast_into::()) + .map(|base| base.cast_into::()) .transpose()? .unwrap_or_else(|| ob.get_type()); @@ -491,7 +493,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython { .map(|params| { params .try_iter()? - .map(|p| Param::extract_no_coerce(&p?)) + .map(|p| Param::extract_no_coerce(p?.as_borrowed())) .collect() }) .transpose() @@ -508,8 +510,8 @@ impl<'py> FromPyObject<'py> for OperationFromPython { // quickly identify them here without an `isinstance` check. let Some(standard) = ob_type .getattr(intern!(py, "_standard_gate")) - .and_then(|standard| standard.extract::()) .ok() + .and_then(|standard| standard.extract::().ok()) else { break 'standard_gate; }; @@ -547,8 +549,8 @@ impl<'py> FromPyObject<'py> for OperationFromPython { // read (e.g. a Barrier's number of qubits) to build the Rust representation. let Some(standard_type) = ob_type .getattr(intern!(py, "_standard_instruction_type")) - .and_then(|standard| standard.extract::()) .ok() + .and_then(|standard| standard.extract::().ok()) else { break 'standard_instr; }; @@ -625,7 +627,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython { clbits: 0, params: params.len() as u32, op_name: ob.getattr(intern!(py, "name"))?.extract()?, - gate: ob.clone().unbind(), + gate: ob.to_owned().unbind(), }); return Ok(OperationFromPython { operation: PackedOperation::from_gate(gate), @@ -641,7 +643,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython { params: params.len() as u32, op_name: ob.getattr(intern!(py, "name"))?.extract()?, control_flow: ob.is_instance(CONTROL_FLOW_OP.get_bound(py))?, - instruction: ob.clone().unbind(), + instruction: ob.to_owned().unbind(), }); return Ok(OperationFromPython { operation: PackedOperation::from_instruction(instruction), @@ -656,7 +658,7 @@ impl<'py> FromPyObject<'py> for OperationFromPython { clbits: ob.getattr(intern!(py, "num_clbits"))?.extract()?, params: params.len() as u32, op_name: ob.getattr(intern!(py, "name"))?.extract()?, - operation: ob.clone().unbind(), + operation: ob.to_owned().unbind(), }); return Ok(OperationFromPython { operation: PackedOperation::from_operation(operation), @@ -664,7 +666,10 @@ impl<'py> FromPyObject<'py> for OperationFromPython { label: None, }); } - Err(PyTypeError::new_err(format!("invalid input: {ob}"))) + Err(PyTypeError::new_err(format!( + "invalid input: {}", + ob.to_owned() + ))) } } @@ -674,9 +679,9 @@ fn as_tuple<'py>(py: Python<'py>, seq: Option>) -> PyResult() { - Ok(seq.downcast_into_exact::()?) + Ok(seq.cast_into_exact::()?) } else if seq.is_instance_of::() { - Ok(seq.downcast_exact::()?.to_tuple()) + Ok(seq.cast_exact::()?.to_tuple()) } else { // New tuple from iterable. PyTuple::new( diff --git a/crates/circuit/src/classical/expr/binary.rs b/crates/circuit/src/classical/expr/binary.rs index 9dbf2212f852..bb3035947ff7 100644 --- a/crates/circuit/src/classical/expr/binary.rs +++ b/crates/circuit/src/classical/expr/binary.rs @@ -76,8 +76,10 @@ impl<'py> IntoPyObject<'py> for Binary { } } -impl<'py> FromPyObject<'py> for Binary { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Binary { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyBinary(b) = ob.extract()?; Ok(b) } @@ -93,8 +95,10 @@ impl<'py> IntoPyObject<'py> for BinaryOp { } } -impl<'py> FromPyObject<'py> for BinaryOp { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for BinaryOp { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let value = ob.getattr(intern!(ob.py(), "value"))?; Ok(bytemuck::checked::cast(value.extract::()?)) } diff --git a/crates/circuit/src/classical/expr/cast.rs b/crates/circuit/src/classical/expr/cast.rs index d98032a94e54..ea3affb38f94 100644 --- a/crates/circuit/src/classical/expr/cast.rs +++ b/crates/circuit/src/classical/expr/cast.rs @@ -36,8 +36,10 @@ impl<'py> IntoPyObject<'py> for Cast { } } -impl<'py> FromPyObject<'py> for Cast { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Cast { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyCast(c) = ob.extract()?; Ok(c) } diff --git a/crates/circuit/src/classical/expr/expr.rs b/crates/circuit/src/classical/expr/expr.rs index 14eeb003ea10..78ab864d4afb 100644 --- a/crates/circuit/src/classical/expr/expr.rs +++ b/crates/circuit/src/classical/expr/expr.rs @@ -453,9 +453,11 @@ impl<'py> IntoPyObject<'py> for Expr { } } -impl<'py> FromPyObject<'py> for Expr { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - let expr: PyRef<'_, PyExpr> = ob.downcast()?.borrow(); +impl<'a, 'py> FromPyObject<'a, 'py> for Expr { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + let expr: PyRef<'_, PyExpr> = ob.cast()?.borrow(); match expr.0 { ExprKind::Unary => Ok(Expr::Unary(Box::new(ob.extract()?))), ExprKind::Binary => Ok(Expr::Binary(Box::new(ob.extract()?))), diff --git a/crates/circuit/src/classical/expr/index.rs b/crates/circuit/src/classical/expr/index.rs index 03ee87c49c31..95ddf6dd7c4a 100644 --- a/crates/circuit/src/classical/expr/index.rs +++ b/crates/circuit/src/classical/expr/index.rs @@ -35,8 +35,10 @@ impl<'py> IntoPyObject<'py> for Index { } } -impl<'py> FromPyObject<'py> for Index { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Index { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyIndex(i) = ob.extract()?; Ok(i) } diff --git a/crates/circuit/src/classical/expr/stretch.rs b/crates/circuit/src/classical/expr/stretch.rs index f777cc28866e..f73e01ab0201 100644 --- a/crates/circuit/src/classical/expr/stretch.rs +++ b/crates/circuit/src/classical/expr/stretch.rs @@ -35,8 +35,10 @@ impl<'py> IntoPyObject<'py> for Stretch { } } -impl<'py> FromPyObject<'py> for Stretch { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Stretch { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyStretch(s) = ob.extract()?; Ok(s) } diff --git a/crates/circuit/src/classical/expr/unary.rs b/crates/circuit/src/classical/expr/unary.rs index d1a279db058c..07d7a38cbc10 100644 --- a/crates/circuit/src/classical/expr/unary.rs +++ b/crates/circuit/src/classical/expr/unary.rs @@ -60,8 +60,10 @@ impl<'py> IntoPyObject<'py> for Unary { } } -impl<'py> FromPyObject<'py> for Unary { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Unary { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyUnary(u) = ob.extract()?; Ok(u) } @@ -77,8 +79,10 @@ impl<'py> IntoPyObject<'py> for UnaryOp { } } -impl<'py> FromPyObject<'py> for UnaryOp { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for UnaryOp { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let value = ob.getattr(intern!(ob.py(), "value"))?; Ok(bytemuck::checked::cast(value.extract::()?)) } diff --git a/crates/circuit/src/classical/expr/value.rs b/crates/circuit/src/classical/expr/value.rs index 208afbec5621..b6ec710ac7f0 100644 --- a/crates/circuit/src/classical/expr/value.rs +++ b/crates/circuit/src/classical/expr/value.rs @@ -35,8 +35,10 @@ impl<'py> IntoPyObject<'py> for Value { } } -impl<'py> FromPyObject<'py> for Value { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Value { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyValue(v) = ob.extract()?; Ok(v) } diff --git a/crates/circuit/src/classical/expr/var.rs b/crates/circuit/src/classical/expr/var.rs index ca30b017714a..5f9db2c92d7e 100644 --- a/crates/circuit/src/classical/expr/var.rs +++ b/crates/circuit/src/classical/expr/var.rs @@ -59,8 +59,10 @@ impl<'py> IntoPyObject<'py> for Var { } } -impl<'py> FromPyObject<'py> for Var { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Var { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyVar(v) = ob.extract()?; Ok(v) } diff --git a/crates/circuit/src/classical/types.rs b/crates/circuit/src/classical/types.rs index eafaacea9100..9451a1c84728 100644 --- a/crates/circuit/src/classical/types.rs +++ b/crates/circuit/src/classical/types.rs @@ -48,8 +48,10 @@ impl<'py> IntoPyObject<'py> for Type { } } -impl<'py> FromPyObject<'py> for Type { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Type { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let PyType(kind) = ob.extract()?; Ok(match kind { TypeKind::Bool => Type::Bool, diff --git a/crates/circuit/src/converters.rs b/crates/circuit/src/converters.rs index 78ee890b289e..d3da5439be78 100644 --- a/crates/circuit/src/converters.rs +++ b/crates/circuit/src/converters.rs @@ -32,8 +32,10 @@ pub struct QuantumCircuitData<'py> { pub metadata: Option>, } -impl<'py> FromPyObject<'py> for QuantumCircuitData<'py> { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for QuantumCircuitData<'py> { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult { let py = ob.py(); let circuit_data = ob.getattr("_data")?; let data_borrowed = circuit_data.extract::()?; diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 3518b3fa2413..d03e43680594 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -255,8 +255,8 @@ fn condition_resources(condition: &Bound) -> PyResult .get_bound(condition.py()) .call1((condition,))?; Ok(PyLegacyResources { - clbits: res.getattr("clbits")?.downcast_into_exact()?.unbind(), - cregs: res.getattr("cregs")?.downcast_into_exact()?.unbind(), + clbits: res.getattr("clbits")?.cast_into_exact()?.unbind(), + cregs: res.getattr("cregs")?.cast_into_exact()?.unbind(), }) } @@ -265,8 +265,8 @@ fn node_resources(node: &Bound) -> PyResult { .get_bound(node.py()) .call1((node,))?; Ok(PyLegacyResources { - clbits: res.getattr("clbits")?.downcast_into_exact()?.unbind(), - cregs: res.getattr("cregs")?.downcast_into_exact()?.unbind(), + clbits: res.getattr("clbits")?.cast_into_exact()?.unbind(), + cregs: res.getattr("cregs")?.cast_into_exact()?.unbind(), }) } @@ -296,11 +296,11 @@ impl PyBitLocations { fn __eq__(slf: Bound, other: Bound) -> PyResult { let borrowed = slf.borrow(); - if let Ok(other) = other.downcast::() { + if let Ok(other) = other.cast::() { let other_borrowed = other.borrow(); Ok(borrowed.index == other_borrowed.index && slf.getattr("registers")?.eq(other.getattr("registers")?)?) - } else if let Ok(other) = other.downcast::() { + } else if let Ok(other) = other.cast::() { Ok(slf.getattr("index")?.eq(other.get_item(0)?)? && slf.getattr("registers")?.eq(other.get_item(1)?)?) } else { @@ -389,7 +389,7 @@ impl DAGVarInfo { } fn from_pickle(ob: &Bound) -> PyResult { - let val_tuple = ob.downcast::()?; + let val_tuple = ob.cast::()?; Ok(DAGVarInfo { var: Var(val_tuple.get_item(0)?.extract()?), type_: match val_tuple.get_item(1)?.extract::()? { @@ -441,7 +441,7 @@ impl DAGStretchInfo { } fn from_pickle(ob: &Bound) -> PyResult { - let val_tuple = ob.downcast::()?; + let val_tuple = ob.cast::()?; Ok(DAGStretchInfo { stretch: Stretch(val_tuple.get_item(0)?.extract()?), type_: match val_tuple.get_item(1)?.extract::()? { @@ -478,7 +478,7 @@ impl DAGIdentifierInfo { } fn from_pickle(ob: &Bound) -> PyResult { - let val_tuple = ob.downcast::()?; + let val_tuple = ob.cast::()?; match val_tuple.get_item(0)?.extract::()? { 0 => Ok(DAGIdentifierInfo::Stretch(DAGStretchInfo::from_pickle( &val_tuple.get_item(1)?, @@ -796,7 +796,7 @@ impl DAGCircuit { } fn __setstate__(&mut self, py: Python, state: Py) -> PyResult<()> { - let dict_state = state.downcast_bound::(py)?; + let dict_state = state.cast_bound::(py)?; self.name = dict_state.get_item("name")?.unwrap().extract()?; self.metadata = dict_state.get_item("metadata")?.unwrap().extract()?; self.qregs = @@ -814,7 +814,7 @@ impl DAGCircuit { self.global_phase = dict_state.get_item("global_phase")?.unwrap().extract()?; self.op_names = dict_state.get_item("op_name")?.unwrap().extract()?; let binding = dict_state.get_item("identifier_info")?.unwrap(); - let identifier_info_raw = binding.downcast::().unwrap(); + let identifier_info_raw = binding.cast::().unwrap(); self.identifier_info = IndexMap::with_capacity_and_hasher(identifier_info_raw.len(), RandomState::default()); for (key, value) in identifier_info_raw.iter() { @@ -854,17 +854,17 @@ impl DAGCircuit { self.clbits.add(bit, false)?; } let binding = dict_state.get_item("vars")?.unwrap(); - let vars_raw = binding.downcast::()?; + let vars_raw = binding.cast::()?; for v in vars_raw.iter() { self.vars.add(v.extract()?, false)?; } let binding = dict_state.get_item("stretches")?.unwrap(); - let stretches_raw = binding.downcast::()?; + let stretches_raw = binding.cast::()?; for s in stretches_raw.iter() { self.stretches.add(s.extract()?, false)?; } let binding = dict_state.get_item("qubit_io_map")?.unwrap(); - let qubit_index_map_raw = binding.downcast::().unwrap(); + let qubit_index_map_raw = binding.cast::().unwrap(); self.qubit_io_map = Vec::with_capacity(qubit_index_map_raw.len()); for (_k, v) in qubit_index_map_raw.iter() { let indices: [usize; 2] = v.extract()?; @@ -872,7 +872,7 @@ impl DAGCircuit { .push([NodeIndex::new(indices[0]), NodeIndex::new(indices[1])]); } let binding = dict_state.get_item("clbit_io_map")?.unwrap(); - let clbit_index_map_raw = binding.downcast::().unwrap(); + let clbit_index_map_raw = binding.cast::().unwrap(); self.clbit_io_map = Vec::with_capacity(clbit_index_map_raw.len()); for (_k, v) in clbit_index_map_raw.iter() { let indices: [usize; 2] = v.extract()?; @@ -880,7 +880,7 @@ impl DAGCircuit { .push([NodeIndex::new(indices[0]), NodeIndex::new(indices[1])]); } let binding = dict_state.get_item("var_io_map")?.unwrap(); - let var_index_map_raw = binding.downcast::().unwrap(); + let var_index_map_raw = binding.cast::().unwrap(); self.var_io_map = Vec::with_capacity(var_index_map_raw.len()); for (_k, v) in var_index_map_raw.iter() { let indices: [usize; 2] = v.extract()?; @@ -889,21 +889,21 @@ impl DAGCircuit { } // Rebuild Graph preserving index holes: let binding = dict_state.get_item("nodes")?.unwrap(); - let nodes_lst = binding.downcast::()?; + let nodes_lst = binding.cast::()?; let binding = dict_state.get_item("edges")?.unwrap(); - let edges_lst = binding.downcast::()?; + let edges_lst = binding.cast::()?; let node_removed: bool = dict_state.get_item("nodes_removed")?.unwrap().extract()?; self.dag = StableDiGraph::default(); if !node_removed { for item in nodes_lst.iter() { - let node_w = item.downcast::().unwrap().get_item(1).unwrap(); + let node_w = item.cast::().unwrap().get_item(1).unwrap(); let weight = self.pack_into(py, &node_w)?; self.dag.add_node(weight); } } else if nodes_lst.len() == 1 { // graph has only one node, handle logic here to save one if in the loop later let binding = nodes_lst.get_item(0).unwrap(); - let item = binding.downcast::().unwrap(); + let item = binding.cast::().unwrap(); let node_idx: usize = item.get_item(0).unwrap().extract().unwrap(); let node_w = item.get_item(1).unwrap(); @@ -917,7 +917,7 @@ impl DAGCircuit { } } else { let binding = nodes_lst.get_item(nodes_lst.len() - 1).unwrap(); - let last_item = binding.downcast::().unwrap(); + let last_item = binding.cast::().unwrap(); // list of temporary nodes that will be removed later to re-create holes let node_bound_1: usize = last_item.get_item(0).unwrap().extract().unwrap(); @@ -925,7 +925,7 @@ impl DAGCircuit { Vec::with_capacity(node_bound_1 + 1 - nodes_lst.len()); for item in nodes_lst { - let item = item.downcast::().unwrap(); + let item = item.cast::().unwrap(); let next_index: usize = item.get_item(0).unwrap().extract().unwrap(); let weight: Py = item.get_item(1).unwrap().extract().unwrap(); while next_index > self.dag.node_bound() { @@ -952,7 +952,7 @@ impl DAGCircuit { self.dag .add_edge(tmp_node, tmp_node, Wire::Qubit(Qubit(u32::MAX))); } else { - let triple = item.downcast::().unwrap(); + let triple = item.cast::().unwrap(); let edge_p: usize = triple.get_item(0).unwrap().extract().unwrap(); let edge_c: usize = triple.get_item(1).unwrap().extract().unwrap(); let edge_w = Wire::from_pickle(&triple.get_item(2).unwrap())?; @@ -1612,7 +1612,7 @@ impl DAGCircuit { if q.is_instance_of::() { Ok(self.qubits.get(Qubit::new(q.extract()?)).unwrap().clone()) } else { - q.extract::() + q.extract::().map_err(Into::into) } }) .collect::>>() @@ -1627,7 +1627,7 @@ impl DAGCircuit { if c.is_instance_of::() { Ok(self.clbits.get(Clbit::new(c.extract()?)).unwrap().clone()) } else { - c.extract::() + c.extract::().map_err(Into::into) } }) .collect::>>() @@ -2581,12 +2581,12 @@ impl DAGCircuit { let mut qubit_pos_map: HashMap = HashMap::new(); let mut clbit_pos_map: HashMap = HashMap::new(); for (bit, index) in wire_pos_map.iter() { - if bit.downcast::().is_ok() { + if bit.cast::().is_ok() { qubit_pos_map.insert( self.qubits.find(&bit.extract::()?).unwrap(), index.extract()?, ); - } else if bit.downcast::().is_ok() { + } else if bit.cast::().is_ok() { clbit_pos_map.insert( self.clbits.find(&bit.extract::()?).unwrap(), index.extract()?, @@ -2655,7 +2655,7 @@ impl DAGCircuit { 2, ))?; } - let node_index = match node.downcast::() { + let node_index = match node.cast::() { Ok(bound_node) => bound_node.borrow().as_ref().node.unwrap(), Err(_) => return Err(DAGCircuitError::new_err("expected node DAGOpNode")), }; @@ -2706,7 +2706,7 @@ impl DAGCircuit { let mut clbit_wire_map = HashMap::new(); let var_map = HashMap::new(); for (index, wire) in wires.iter().enumerate() { - if wire.downcast::().is_ok() { + if wire.cast::().is_ok() { if index >= qargs_len { unreachable!() } @@ -2716,7 +2716,7 @@ impl DAGCircuit { .unwrap(); let self_qubit: Qubit = self.qubits.find(qargs_list[index]).unwrap(); qubit_wire_map.insert(input_qubit, self_qubit); - } else if wire.downcast::().is_ok() { + } else if wire.cast::().is_ok() { if index < qargs_len { unreachable!() } @@ -2741,13 +2741,13 @@ impl DAGCircuit { HashMap, HashMap, ) = match wires { - Some(wires) => match wires.downcast::() { + Some(wires) => match wires.cast::() { Ok(bound_wires) => { let mut qubit_wire_map = HashMap::new(); let mut clbit_wire_map = HashMap::new(); let mut var_map = HashMap::new(); for (source_wire, target_wire) in bound_wires.iter() { - if source_wire.downcast::().is_ok() { + if source_wire.cast::().is_ok() { qubit_wire_map.insert( input_dag .qubits @@ -2757,7 +2757,7 @@ impl DAGCircuit { .find(&target_wire.extract::()?) .unwrap(), ); - } else if source_wire.downcast::().is_ok() { + } else if source_wire.cast::().is_ok() { clbit_wire_map.insert( input_dag .clbits @@ -2774,7 +2774,7 @@ impl DAGCircuit { (qubit_wire_map, clbit_wire_map, var_map) } Err(_) => { - let wires: Bound = match wires.downcast::() { + let wires: Bound = match wires.cast::() { Ok(bound_list) => bound_list.clone(), // If someone passes a sequence instead of an exact list (tuple is // occasionally used) cast that to a list and then use it. @@ -2915,7 +2915,7 @@ impl DAGCircuit { 2, ))?; } - let mut node: PyRefMut = match node.downcast() { + let mut node: PyRefMut = match node.cast() { Ok(node) => node.borrow_mut(), Err(_) => return Err(DAGCircuitError::new_err("Only DAGOpNodes can be replaced.")), }; @@ -3062,7 +3062,7 @@ impl DAGCircuit { .idle_wires(py, None)? .into_bound(py) .map(|q| q.unwrap()) - .filter(|e| e.downcast::().is_ok()) + .filter(|e| e.cast::().is_ok()) .collect(); let qubits = PyTuple::new(py, idle_wires)?; @@ -3208,7 +3208,7 @@ impl DAGCircuit { #[pyo3(signature=(nodes=None))] fn edges(&self, py: Python, nodes: Option>) -> PyResult> { let get_node_index = |obj: &Bound| -> PyResult { - Ok(obj.downcast::()?.borrow().node.unwrap()) + Ok(obj.cast::()?.borrow().node.unwrap()) }; let actual_nodes: Vec<_> = match nodes { @@ -3599,7 +3599,7 @@ impl DAGCircuit { /// Add edges from predecessors to successors. #[pyo3(name = "remove_op_node")] fn py_remove_op_node(&mut self, node: &Bound) -> PyResult<()> { - let node: PyRef = match node.downcast::() { + let node: PyRef = match node.cast::() { Ok(node) => node.borrow(), Err(_) => return Err(DAGCircuitError::new_err("Node not an DAGOpNode")), }; @@ -3910,10 +3910,10 @@ impl DAGCircuit { wire: &Bound, only_ops: bool, ) -> PyResult> { - let wire = if wire.downcast::().is_ok() { + let wire = if wire.cast::().is_ok() { let wire = wire.extract::()?; self.qubits.find(&wire).map(Wire::Qubit) - } else if wire.downcast::().is_ok() { + } else if wire.cast::().is_ok() { let wire = wire.extract::()?; self.clbits.find(&wire).map(Wire::Clbit) } else { @@ -5758,7 +5758,7 @@ impl DAGCircuit { } if op.is_instance(imports::SWITCH_CASE_OP.get_bound(py))? { let target = op.getattr(intern!(py, "target"))?; - if target.downcast::().is_ok() { + if target.cast::().is_ok() { let target_clbit: ShareableClbit = target.extract()?; clbits.push(self.clbits.find(&target_clbit).unwrap()); } else if target.is_instance_of::() { @@ -5968,7 +5968,7 @@ impl DAGCircuit { } fn pack_into(&mut self, py: Python, b: &Bound) -> Result { - Ok(if let Ok(in_node) = b.downcast::() { + Ok(if let Ok(in_node) = b.cast::() { let in_node = in_node.borrow(); let wire = in_node.wire.bind(py); if let Ok(qubit) = wire.extract::() { @@ -5979,7 +5979,7 @@ impl DAGCircuit { let var = wire.extract::()?; NodeType::VarIn(self.vars.find(&var).unwrap()) } - } else if let Ok(out_node) = b.downcast::() { + } else if let Ok(out_node) = b.cast::() { let out_node = out_node.borrow(); let wire = out_node.wire.bind(py); if let Ok(qubit) = wire.extract::() { @@ -5990,7 +5990,7 @@ impl DAGCircuit { let var = wire.extract::()?; NodeType::VarOut(self.vars.find(&var).unwrap()) } - } else if let Ok(op_node) = b.downcast::() { + } else if let Ok(op_node) = b.cast::() { let op_node = op_node.borrow(); let qubits = self.qargs_interner.insert_owned( self.qubits @@ -7258,7 +7258,7 @@ impl DAGCircuit { Python::attach(|py| -> PyResult<()> { let op_bound = op.instruction.bind(py); let target = op_bound.getattr(intern!(py, "target"))?; - if target.downcast::().is_ok() { + if target.cast::().is_ok() { let target_clbit: ShareableClbit = target.extract()?; block_cargs.insert(self.clbits.find(&target_clbit).unwrap()); } else if target.is_instance_of::() { diff --git a/crates/circuit/src/dag_node.rs b/crates/circuit/src/dag_node.rs index d052dde1a9c9..eb0fdedf825f 100644 --- a/crates/circuit/src/dag_node.rs +++ b/crates/circuit/src/dag_node.rs @@ -158,7 +158,7 @@ impl DAGOpNode { // like parameter equality are stricter to reject things like // Param::Float(0.1) == Param::ParameterExpression(0.1) (if the expression was // a python parameter equivalent to a bound value). - let Ok(other) = other.downcast::() else { + let Ok(other) = other.cast::() else { return Ok(false); }; let borrowed_other = other.borrow(); @@ -474,7 +474,7 @@ impl DAGInNode { } fn __eq__(slf: PyRef, py: Python, other: &Bound) -> PyResult { - match other.downcast::() { + match other.cast::() { Ok(other) => { let borrowed_other = other.borrow(); let other_super = borrowed_other.as_ref(); @@ -537,7 +537,7 @@ impl DAGOutNode { } fn __eq__(slf: PyRef, py: Python, other: &Bound) -> PyResult { - match other.downcast::() { + match other.cast::() { Ok(other) => { let borrowed_other = other.borrow(); let other_super = borrowed_other.as_ref(); diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index 8ad71078cdc1..9dbe817baed5 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -108,9 +108,11 @@ pub struct TupleLikeArg<'py> { value: Bound<'py, PyTuple>, } -impl<'py> FromPyObject<'py> for TupleLikeArg<'py> { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - let value = match ob.downcast::() { +impl<'a, 'py> FromPyObject<'a, 'py> for TupleLikeArg<'py> { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + let value = match ob.cast::() { Ok(seq) => seq.to_tuple()?, Err(_) => PyTuple::new( ob.py(), @@ -170,9 +172,11 @@ pub enum VarsMode { Drop, } -impl<'py> FromPyObject<'py> for VarsMode { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - match &*ob.downcast::()?.to_string_lossy() { +impl<'a, 'py> FromPyObject<'a, 'py> for VarsMode { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + match &*ob.cast::()?.to_string_lossy() { "alike" => Ok(VarsMode::Alike), "captures" => Ok(VarsMode::Captures), "drop" => Ok(VarsMode::Drop), diff --git a/crates/circuit/src/nlayout.rs b/crates/circuit/src/nlayout.rs index 91ed1460695e..d253b4cd0cd1 100644 --- a/crates/circuit/src/nlayout.rs +++ b/crates/circuit/src/nlayout.rs @@ -72,9 +72,11 @@ macro_rules! qubit_newtype { } } - impl pyo3::FromPyObject<'_> for $id { - fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { - Ok(Self(ob.extract()?)) + impl<'a, 'py> ::pyo3::FromPyObject<'a, 'py> for $id { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { + ob.extract().map(Self) } } diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index a16ed25c11e1..5b250323b161 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -72,14 +72,16 @@ impl<'py> IntoPyObject<'py> for Param { } } -impl<'py> FromPyObject<'py> for Param { - fn extract_bound(b: &Bound<'py, PyAny>) -> Result { +impl<'a, 'py> FromPyObject<'a, 'py> for Param { + type Error = ::std::convert::Infallible; + + fn extract(b: Borrowed<'a, 'py, PyAny>) -> Result { Ok(if let Ok(py_expr) = b.extract::() { Param::ParameterExpression(Arc::new(py_expr.inner)) } else if let Ok(val) = b.extract::() { Param::Float(val) } else { - Param::Obj(b.clone().unbind()) + Param::Obj(b.to_owned().unbind()) }) } } @@ -130,7 +132,7 @@ impl Param { .try_iter()? .map(|elem| { let elem = elem?; - let py_param_bound = elem.downcast::()?; + let py_param_bound = elem.cast::()?; let py_param = py_param_bound.borrow(); let symbol = py_param.symbol(); Ok(symbol.clone()) @@ -187,19 +189,19 @@ impl Param { /// Extract from a Python object without numeric coercion to float. The default conversion will /// coerce integers into floats, but in things like `assign_parameters`, this is not always /// desirable. - pub fn extract_no_coerce(ob: &Bound) -> PyResult { + pub fn extract_no_coerce(ob: Borrowed) -> PyResult { Ok(if ob.is_instance_of::() { Param::Float(ob.extract()?) } else if let Ok(py_expr) = PyParameterExpression::extract_coerce(ob) { // don't get confused by the `coerce` name here -- we promise to not coerce to // Param::Float. But if it's an int or complex we need to store it as an Obj. if Some(true) == py_expr.inner.is_int() || Some(true) == py_expr.inner.is_complex() { - Param::Obj(ob.clone().unbind()) + Param::Obj(ob.to_owned().unbind()) } else { Param::ParameterExpression(Arc::new(py_expr.inner)) } } else { - Param::Obj(ob.clone().unbind()) + Param::Obj(ob.to_owned().unbind()) }) } @@ -222,7 +224,9 @@ impl Param { _ => DEEPCOPY .get_bound(py) .call1((self.clone(), memo))? - .extract(), + .extract() + // The extraction is infallible. + .map_err(|x| match x {}), } } } @@ -431,8 +435,10 @@ impl fmt::Display for DelayUnit { } } -impl<'py> FromPyObject<'py> for DelayUnit { - fn extract_bound(b: &Bound<'py, PyAny>) -> Result { +impl<'a, 'py> FromPyObject<'a, 'py> for DelayUnit { + type Error = PyErr; + + fn extract(b: Borrowed<'a, 'py, PyAny>) -> Result { let str: String = b.extract()?; Ok(match str.as_str() { "ns" => DelayUnit::NS, @@ -2512,7 +2518,7 @@ impl Operation for PyInstruction { // We expect that if PyInstruction::control_flow is true then the operation WILL // have a 'blocks' attribute which is a tuple of the Python QuantumCircuit. let raw_blocks = self.instruction.getattr(py, "blocks").unwrap(); - let blocks: &Bound = raw_blocks.downcast_bound::(py).unwrap(); + let blocks: &Bound = raw_blocks.cast_bound::(py).unwrap(); blocks .iter() .map(|b| { diff --git a/crates/circuit/src/packed_instruction.rs b/crates/circuit/src/packed_instruction.rs index b49520cd85a0..f1817057a881 100644 --- a/crates/circuit/src/packed_instruction.rs +++ b/crates/circuit/src/packed_instruction.rs @@ -459,27 +459,23 @@ impl PackedOperation { OperationRef::StandardGate(standard) => { return get_std_gate_class(py, standard)? .bind(py) - .downcast::()? + .cast::()? .is_subclass(py_type); } OperationRef::StandardInstruction(standard) => { return match standard { - StandardInstruction::Barrier(_) => BARRIER - .get_bound(py) - .downcast::()? - .is_subclass(py_type), - StandardInstruction::Delay(_) => DELAY - .get_bound(py) - .downcast::()? - .is_subclass(py_type), - StandardInstruction::Measure => MEASURE - .get_bound(py) - .downcast::()? - .is_subclass(py_type), - StandardInstruction::Reset => RESET - .get_bound(py) - .downcast::()? - .is_subclass(py_type), + StandardInstruction::Barrier(_) => { + BARRIER.get_bound(py).cast::()?.is_subclass(py_type) + } + StandardInstruction::Delay(_) => { + DELAY.get_bound(py).cast::()?.is_subclass(py_type) + } + StandardInstruction::Measure => { + MEASURE.get_bound(py).cast::()?.is_subclass(py_type) + } + StandardInstruction::Reset => { + RESET.get_bound(py).cast::()?.is_subclass(py_type) + } }; } OperationRef::Gate(gate) => gate.gate.bind(py), @@ -488,7 +484,7 @@ impl PackedOperation { OperationRef::Unitary(_) => { return UNITARY_GATE .get_bound(py) - .downcast::()? + .cast::()? .is_subclass(py_type); } }; diff --git a/crates/circuit/src/parameter/parameter_expression.rs b/crates/circuit/src/parameter/parameter_expression.rs index f6dbe0cfaa06..20cb66298226 100644 --- a/crates/circuit/src/parameter/parameter_expression.rs +++ b/crates/circuit/src/parameter/parameter_expression.rs @@ -727,31 +727,31 @@ impl PyParameterExpression { /// /// * `Ok(Self)` - The extracted expression. /// * `Err(PyResult)` - An error if extraction to all above types failed. - pub fn extract_coerce(ob: &Bound<'_, PyAny>) -> PyResult { - if let Ok(i) = ob.downcast::() { + pub fn extract_coerce(ob: Borrowed) -> PyResult { + if let Ok(i) = ob.cast::() { Ok(ParameterExpression::new( SymbolExpr::Value(Value::from(i.extract::()?)), HashMap::new(), ) .into()) - } else if let Ok(r) = ob.downcast::() { + } else if let Ok(r) = ob.cast::() { let r: f64 = r.extract()?; if r.is_infinite() || r.is_nan() { return Err(ParameterError::InvalidValue.into()); } Ok(ParameterExpression::new(SymbolExpr::Value(Value::from(r)), HashMap::new()).into()) - } else if let Ok(c) = ob.downcast::() { + } else if let Ok(c) = ob.cast::() { let c: Complex64 = c.extract()?; if c.is_infinite() || c.is_nan() { return Err(ParameterError::InvalidValue.into()); } Ok(ParameterExpression::new(SymbolExpr::Value(Value::from(c)), HashMap::new()).into()) - } else if let Ok(element) = ob.downcast::() { + } else if let Ok(element) = ob.cast::() { Ok(ParameterExpression::from_symbol(element.borrow().symbol.clone()).into()) - } else if let Ok(parameter) = ob.downcast::() { + } else if let Ok(parameter) = ob.cast::() { Ok(ParameterExpression::from_symbol(parameter.borrow().symbol.clone()).into()) } else { - ob.extract::() + ob.extract::().map_err(Into::into) } } @@ -816,7 +816,7 @@ impl PyParameterExpression { #[allow(non_snake_case)] #[staticmethod] pub fn _Value(value: &Bound) -> PyResult { - Self::extract_coerce(value) + Self::extract_coerce(value.as_borrowed()) } /// Check if the expression corresponds to a plain symbol. @@ -1127,7 +1127,7 @@ impl PyParameterExpression { /// A new expression parameterized by any parameters which were not bound by assignment. #[pyo3(name = "assign")] pub fn py_assign(&self, parameter: PyParameter, value: &Bound) -> PyResult { - if let Ok(expr) = value.downcast::() { + if let Ok(expr) = value.cast::() { let map = [(parameter, expr.borrow().clone())].into_iter().collect(); self.py_subs(map, false) } else if value.extract::().is_ok() { @@ -1153,7 +1153,7 @@ impl PyParameterExpression { } pub fn __eq__(&self, rhs: &Bound) -> PyResult { - if let Ok(rhs) = Self::extract_coerce(rhs) { + if let Ok(rhs) = Self::extract_coerce(rhs.as_borrowed()) { match rhs.inner.expr { SymbolExpr::Value(v) => match self.inner.try_to_value(false) { Ok(e) => Ok(e == v), @@ -1183,7 +1183,7 @@ impl PyParameterExpression { } pub fn __add__(&self, rhs: &Bound) -> PyResult { - if let Ok(rhs) = Self::extract_coerce(rhs) { + if let Ok(rhs) = Self::extract_coerce(rhs.as_borrowed()) { Ok(self.inner.add(&rhs.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1193,7 +1193,7 @@ impl PyParameterExpression { } pub fn __radd__(&self, lhs: &Bound) -> PyResult { - if let Ok(lhs) = Self::extract_coerce(lhs) { + if let Ok(lhs) = Self::extract_coerce(lhs.as_borrowed()) { Ok(lhs.inner.add(&self.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1203,7 +1203,7 @@ impl PyParameterExpression { } pub fn __sub__(&self, rhs: &Bound) -> PyResult { - if let Ok(rhs) = Self::extract_coerce(rhs) { + if let Ok(rhs) = Self::extract_coerce(rhs.as_borrowed()) { Ok(self.inner.sub(&rhs.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1213,7 +1213,7 @@ impl PyParameterExpression { } pub fn __rsub__(&self, lhs: &Bound) -> PyResult { - if let Ok(lhs) = Self::extract_coerce(lhs) { + if let Ok(lhs) = Self::extract_coerce(lhs.as_borrowed()) { Ok(lhs.inner.sub(&self.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1224,7 +1224,7 @@ impl PyParameterExpression { pub fn __mul__<'py>(&self, rhs: &Bound<'py, PyAny>) -> PyResult> { let py = rhs.py(); - if let Ok(rhs) = Self::extract_coerce(rhs) { + if let Ok(rhs) = Self::extract_coerce(rhs.as_borrowed()) { match self.inner.mul(&rhs.inner) { Ok(result) => PyParameterExpression::from(result).into_bound_py_any(py), Err(e) => Err(PyErr::from(e)), @@ -1235,7 +1235,7 @@ impl PyParameterExpression { } pub fn __rmul__(&self, lhs: &Bound) -> PyResult { - if let Ok(lhs) = Self::extract_coerce(lhs) { + if let Ok(lhs) = Self::extract_coerce(lhs.as_borrowed()) { Ok(lhs.inner.mul(&self.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1245,7 +1245,7 @@ impl PyParameterExpression { } pub fn __truediv__(&self, rhs: &Bound) -> PyResult { - if let Ok(rhs) = Self::extract_coerce(rhs) { + if let Ok(rhs) = Self::extract_coerce(rhs.as_borrowed()) { Ok(self.inner.div(&rhs.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1255,7 +1255,7 @@ impl PyParameterExpression { } pub fn __rtruediv__(&self, lhs: &Bound) -> PyResult { - if let Ok(lhs) = Self::extract_coerce(lhs) { + if let Ok(lhs) = Self::extract_coerce(lhs.as_borrowed()) { Ok(lhs.inner.div(&self.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1265,7 +1265,7 @@ impl PyParameterExpression { } pub fn __pow__(&self, rhs: &Bound, _modulo: Option) -> PyResult { - if let Ok(rhs) = Self::extract_coerce(rhs) { + if let Ok(rhs) = Self::extract_coerce(rhs.as_borrowed()) { Ok(self.inner.pow(&rhs.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1275,7 +1275,7 @@ impl PyParameterExpression { } pub fn __rpow__(&self, lhs: &Bound, _modulo: Option) -> PyResult { - if let Ok(lhs) = Self::extract_coerce(lhs) { + if let Ok(lhs) = Self::extract_coerce(lhs.as_borrowed()) { Ok(lhs.inner.pow(&self.inner)?.into()) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -1600,7 +1600,7 @@ impl PyParameter { } Some(replacement) => { if allow_unknown_parameters || parameter_values.len() == 1 { - let expr = PyParameterExpression::extract_coerce(replacement)?; + let expr = PyParameterExpression::extract_coerce(replacement.as_borrowed())?; if let SymbolExpr::Value(_) = &expr.inner.expr { expr.clone().into_bound_py_any(py) } else { @@ -1631,7 +1631,7 @@ impl PyParameter { parameter: PyParameter, value: &Bound<'py, PyAny>, ) -> PyResult> { - if value.downcast::().is_ok() { + if value.cast::().is_ok() { let map = [(parameter, value.clone())].into_iter().collect(); self.py_subs(py, map, false) } else if value.extract::().is_ok() { @@ -1942,7 +1942,7 @@ impl OpCode { } fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool { - if let Ok(code) = other.downcast::() { + if let Ok(code) = other.cast::() { *code.borrow() == *self } else { false diff --git a/crates/circuit/src/parameter/symbol_expr.rs b/crates/circuit/src/parameter/symbol_expr.rs index 6217f6b6ee39..8e471c2faca2 100644 --- a/crates/circuit/src/parameter/symbol_expr.rs +++ b/crates/circuit/src/parameter/symbol_expr.rs @@ -12,7 +12,6 @@ use hashbrown::HashMap; use pyo3::IntoPyObjectExt; -use pyo3::exceptions::PyTypeError; use pyo3::exceptions::PyValueError; use std::cmp::Ordering; use std::cmp::PartialOrd; @@ -61,14 +60,16 @@ impl Hash for Symbol { } } -impl<'py> FromPyObject<'py> for Symbol { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Symbol { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { if let Ok(py_vector_element) = ob.extract::() { Ok(py_vector_element.symbol().clone()) - } else if let Ok(py_param) = ob.extract::() { - Ok(py_param.symbol().clone()) } else { - Err(PyTypeError::new_err("Cannot extract Symbol from {ob:?}")) + ob.extract::() + .map(|ob| ob.symbol().clone()) + .map_err(PyErr::from) } } } @@ -156,18 +157,16 @@ pub enum Value { Complex(Complex64), } -impl<'py> FromPyObject<'py> for Value { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Value { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { if let Ok(i) = ob.extract::() { Ok(Value::Int(i)) } else if let Ok(r) = ob.extract::() { Ok(Value::Real(r)) - } else if let Ok(c) = ob.extract::() { - Ok(Value::Complex(c)) } else { - Err(PyValueError::new_err( - "Could not cast Bound to Value.", - )) + ob.extract::().map(Value::Complex) } } } diff --git a/crates/circuit/src/parameter_table.rs b/crates/circuit/src/parameter_table.rs index 3dcee2e674c7..cf801da42298 100644 --- a/crates/circuit/src/parameter_table.rs +++ b/crates/circuit/src/parameter_table.rs @@ -62,10 +62,10 @@ impl ParameterUuid { /// Extract a UUID from a Python-space `Parameter` object. This assumes that the object is known /// to be a parameter. pub fn from_parameter(ob: &Bound) -> PyResult { - let uuid = if let Ok(param) = ob.downcast::() { + let uuid = if let Ok(param) = ob.cast::() { // this downcast should cover both PyParameterVectorElement and PyParameter param.borrow().symbol().uuid.as_u128() - } else if let Ok(expr) = ob.downcast::() { + } else if let Ok(expr) = ob.cast::() { let expr_borrowed = expr.borrow(); // We know the ParameterExpression is in fact representing a single Symbol let symbol = &expr_borrowed.inner.try_to_symbol()?; diff --git a/crates/circuit/src/slice.rs b/crates/circuit/src/slice.rs index 72cd5ed4b7ee..51c6b2f042fc 100644 --- a/crates/circuit/src/slice.rs +++ b/crates/circuit/src/slice.rs @@ -28,16 +28,18 @@ pub enum PySequenceIndex<'py> { Slice(Bound<'py, PySlice>), } -impl<'py> FromPyObject<'py> for PySequenceIndex<'py> { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for PySequenceIndex<'py> { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { // `slice` can't be subclassed in Python, so it's safe (and faster) to check for it exactly. - // The `downcast_exact` check is just a pointer comparison, so while `slice` is the less + // The `cast_exact` check is just a pointer comparison, so while `slice` is the less // common input, doing that first has little-to-no impact on the speed of the `isize` path, // while the reverse makes `slice` inputs significantly slower. - if let Ok(slice) = ob.downcast_exact::() { - return Ok(Self::Slice(slice.clone())); + if let Ok(slice) = ob.cast_exact::() { + return Ok(Self::Slice(slice.to_owned())); } - Ok(Self::Int(ob.extract()?)) + ob.extract().map(Self::Int) } } diff --git a/crates/circuit/src/variable_mapper.rs b/crates/circuit/src/variable_mapper.rs index e30ca6e2b65d..f49f9192ed57 100644 --- a/crates/circuit/src/variable_mapper.rs +++ b/crates/circuit/src/variable_mapper.rs @@ -14,7 +14,6 @@ use crate::bit::{ClassicalRegister, Register, ShareableClbit}; use crate::classical::expr; use hashbrown::{HashMap, HashSet}; use pyo3::prelude::*; -use pyo3::{Bound, FromPyObject, PyAny, PyResult}; use std::cell::RefCell; /// A control flow operation's condition. @@ -27,8 +26,10 @@ pub(crate) enum Condition { Expr(expr::Expr), } -impl<'py> FromPyObject<'py> for Condition { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Condition { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { if let Ok((bit, value)) = ob.extract::<(ShareableClbit, usize)>() { Ok(Condition::Bit(bit, value)) } else if let Ok((register, value)) = ob.extract::<(ClassicalRegister, usize)>() { @@ -49,8 +50,10 @@ pub(crate) enum SwitchTarget { Expr(expr::Expr), } -impl<'py> FromPyObject<'py> for SwitchTarget { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for SwitchTarget { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { if let Ok(bit) = ob.extract::() { Ok(SwitchTarget::Bit(bit)) } else if let Ok(register) = ob.extract::() { diff --git a/crates/circuit_library/src/blocks.rs b/crates/circuit_library/src/blocks.rs index 476ce2951ce6..0ee2ca34680f 100644 --- a/crates/circuit_library/src/blocks.rs +++ b/crates/circuit_library/src/blocks.rs @@ -45,13 +45,13 @@ impl BlockOperation { let py_params = PyList::new(py, params.iter().map(|&p| p.clone()))?.into_any(); let job = builder.call1(py, (py_params,))?; - let result = job.downcast_bound::(py)?; + let result = job.cast_bound::(py)?; let operation: OperationFromPython = result.get_item(0)?.extract()?; let bound_params = result .get_item(1)? .try_iter()? - .map(|ob| Param::extract_no_coerce(&ob?)) + .map(|ob| Param::extract_no_coerce(ob?.as_borrowed())) .collect::>>()?; Ok((operation.operation, bound_params)) @@ -134,10 +134,10 @@ impl Entanglement { .map(|layer| -> PyResult { if entanglement.is_callable() { let as_any = entanglement.call1((layer,))?; - let as_list = as_any.downcast::()?; + let as_list = as_any.cast::()?; unpack_entanglement(num_qubits, layer, as_list, entanglement_blocks) } else { - let as_list = entanglement.downcast::()?; + let as_list = entanglement.cast::()?; unpack_entanglement(num_qubits, layer, as_list, entanglement_blocks) } }) diff --git a/crates/circuit_library/src/entanglement.rs b/crates/circuit_library/src/entanglement.rs index 2ed6c922cac8..942a7f23a2b7 100644 --- a/crates/circuit_library/src/entanglement.rs +++ b/crates/circuit_library/src/entanglement.rs @@ -166,19 +166,19 @@ pub fn get_entanglement<'a>( entanglement.to_owned() }; - if let Ok(strategy) = entanglement.downcast::() { + if let Ok(strategy) = entanglement.cast::() { let as_str = strategy.to_string(); return Ok(Box::new( get_entanglement_from_str(num_qubits, block_size, as_str.as_str(), offset)?.map(Ok), )); - } else if let Ok(dict) = entanglement.downcast::() { + } else if let Ok(dict) = entanglement.cast::() { if let Some(value) = dict.get_item(block_size)? { - let list = value.downcast::()?; + let list = value.cast::()?; return _check_entanglement_list(list.to_owned(), block_size); } else { return Ok(Box::new(std::iter::empty())); } - } else if let Ok(list) = entanglement.downcast::() { + } else if let Ok(list) = entanglement.cast::() { return _check_entanglement_list(list.to_owned(), block_size); } Err(QiskitError::new_err( diff --git a/crates/circuit_library/src/parameter_ledger.rs b/crates/circuit_library/src/parameter_ledger.rs index 7238bc55889e..5bd1c9a948f4 100644 --- a/crates/circuit_library/src/parameter_ledger.rs +++ b/crates/circuit_library/src/parameter_ledger.rs @@ -106,7 +106,7 @@ impl ParameterLedger { .get_bound(py) .call1((parameter_prefix, num_parameters))? // get the Python ParameterVector .try_iter()? // iterate over the elements and cast them to Rust Params - .map(|ob| Param::extract_no_coerce(&ob?)) + .map(|ob| Param::extract_no_coerce(ob?.as_borrowed())) .collect::>()?; // finally, distribute the parameters onto the repetitions and blocks for each diff --git a/crates/circuit_library/src/pauli_evolution.rs b/crates/circuit_library/src/pauli_evolution.rs index 3538274d7dce..bc3a916c0d07 100644 --- a/crates/circuit_library/src/pauli_evolution.rs +++ b/crates/circuit_library/src/pauli_evolution.rs @@ -358,9 +358,9 @@ pub fn py_pauli_evolution( let mut modified_phase = false; // keep track of whether we modified the phase for el in sparse_paulis.iter() { - let tuple = el.downcast::()?; - let pauli = tuple.get_item(0)?.downcast::()?.to_string(); - let time = Param::extract_no_coerce(&tuple.get_item(2)?)?; + let tuple = el.cast::()?; + let pauli = tuple.get_borrowed_item(0)?.cast::()?.to_string(); + let time = Param::extract_no_coerce(tuple.get_borrowed_item(2)?)?; if pauli.as_str().chars().all(|p| p == 'i') { global_phase = radd_param(global_phase, time); diff --git a/crates/circuit_library/src/pauli_feature_map.rs b/crates/circuit_library/src/pauli_feature_map.rs index b76af997860b..c86a15bdb3f6 100644 --- a/crates/circuit_library/src/pauli_feature_map.rs +++ b/crates/circuit_library/src/pauli_feature_map.rs @@ -73,7 +73,7 @@ pub fn pauli_feature_map( // extract the parameters from the input variable ``parameters`` let parameter_vector = parameters .try_iter()? - .map(|el| Param::extract_no_coerce(&el?)) + .map(|el| Param::extract_no_coerce(el?.as_borrowed())) .collect::>>()?; // construct a Barrier object Python side to (possibly) add to the circuit @@ -230,7 +230,7 @@ fn _get_paulis( v.iter() // iterate over the list of Paulis .map(|el| { // Get the string and check whether it fits the feature dimension - let as_string = (*el.downcast::()?).to_string(); + let as_string = (*el.cast::()?).to_string(); if as_string.len() > feature_dimension as usize { Err(QiskitError::new_err(format!( "feature_dimension ({feature_dimension}) smaller than the Pauli ({as_string})" diff --git a/crates/qasm3/src/build.rs b/crates/qasm3/src/build.rs index 718620d96cd3..0154feca8281 100644 --- a/crates/qasm3/src/build.rs +++ b/crates/qasm3/src/build.rs @@ -216,7 +216,7 @@ impl BuilderState { self.qc .inner(py) .getattr("qubits")? - .downcast::()? + .cast::()? .to_tuple()? }; let instruction = self.module.new_instruction( diff --git a/crates/qasm3/src/circuit.rs b/crates/qasm3/src/circuit.rs index dc0224c6aad3..40765ee523c5 100644 --- a/crates/qasm3/src/circuit.rs +++ b/crates/qasm3/src/circuit.rs @@ -198,26 +198,23 @@ impl PyCircuitModule { Ok(Self { circuit: module .getattr("QuantumCircuit")? - .downcast_into::()? + .cast_into::()? .unbind(), qreg: module .getattr("QuantumRegister")? - .downcast_into::()? + .cast_into::()? .unbind(), - qubit: module.getattr("Qubit")?.downcast_into::()?.unbind(), + qubit: module.getattr("Qubit")?.cast_into::()?.unbind(), creg: module .getattr("ClassicalRegister")? - .downcast_into::()? + .cast_into::()? .unbind(), - clbit: module.getattr("Clbit")?.downcast_into::()?.unbind(), + clbit: module.getattr("Clbit")?.cast_into::()?.unbind(), circuit_instruction: module .getattr("CircuitInstruction")? - .downcast_into::()? - .unbind(), - barrier: module - .getattr("Barrier")? - .downcast_into::()? + .cast_into::()? .unbind(), + barrier: module.getattr("Barrier")?.cast_into::()?.unbind(), // Measure is a singleton, so just store the object. measure: module.getattr("Measure")?.call0()?.into_py_any(py)?, }) @@ -237,7 +234,7 @@ impl PyCircuitModule { Ok(PyQuantumRegister { items: PyList::type_object(py) .call1((qreg.clone(),))? - .downcast_into::()? + .cast_into::()? .unbind(), object: qreg, }) @@ -257,7 +254,7 @@ impl PyCircuitModule { Ok(PyClassicalRegister { items: PyList::type_object(py) .call1((creg.clone(),))? - .downcast_into::()? + .cast_into::()? .unbind(), object: creg, }) diff --git a/crates/qasm3/src/lib.rs b/crates/qasm3/src/lib.rs index 84021074e870..afd32ba585bf 100644 --- a/crates/qasm3/src/lib.rs +++ b/crates/qasm3/src/lib.rs @@ -203,10 +203,7 @@ pub fn dumps( options.indent = val.extract::()?; } } - let circuit_data = circuit - .getattr("_data")? - .downcast::()? - .borrow(); + let circuit_data = circuit.getattr("_data")?.cast::()?.borrow(); let islayout = !circuit.getattr("layout")?.is_none(); @@ -254,10 +251,7 @@ pub fn dump( options.indent = val.extract::()?; } } - let circuit_data = circuit - .getattr("_data")? - .downcast::()? - .borrow(); + let circuit_data = circuit.getattr("_data")?.cast::()?.borrow(); let islayout = !circuit.getattr("layout")?.is_none(); diff --git a/crates/quantum_info/src/pauli_lindblad_map/pauli_lindblad_map_class.rs b/crates/quantum_info/src/pauli_lindblad_map/pauli_lindblad_map_class.rs index 25358b23ac9a..b0c9e1645b29 100644 --- a/crates/quantum_info/src/pauli_lindblad_map/pauli_lindblad_map_class.rs +++ b/crates/quantum_info/src/pauli_lindblad_map/pauli_lindblad_map_class.rs @@ -599,7 +599,7 @@ impl PyGeneratorTerm { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf = slf.borrow(); @@ -884,7 +884,7 @@ impl PyPauliLindbladMap { "explicitly given 'num_qubits' ({num_qubits}) does not match operator ({other_qubits})" ))) }; - if let Ok(pauli_lindblad_map) = data.downcast_exact::() { + if let Ok(pauli_lindblad_map) = data.cast_exact::() { check_num_qubits(data)?; let borrowed = pauli_lindblad_map.borrow(); let inner = borrowed.inner.read().map_err(|_| InnerReadError)?; @@ -904,7 +904,7 @@ impl PyPauliLindbladMap { }; return Self::from_sparse_list(vec, num_qubits); } - if let Ok(term) = data.downcast_exact::() { + if let Ok(term) = data.cast_exact::() { return term.borrow().to_pauli_lindblad_map(); }; if let Ok(pauli_lindblad_map) = Self::from_terms(data, num_qubits) { @@ -1047,12 +1047,12 @@ impl PyPauliLindbladMap { "cannot construct a PauliLindbladMap from an empty list without knowing `num_qubits`", )); }; - let py_term = first?.downcast::()?.borrow(); + let py_term = first?.cast::()?.borrow(); py_term.inner.to_pauli_lindblad_map()? } }; for bound_py_term in iter { - let py_term = bound_py_term?.downcast::()?.borrow(); + let py_term = bound_py_term?.cast::()?.borrow(); inner.add_term(py_term.inner.view())?; } Ok(inner.into()) @@ -1728,7 +1728,7 @@ impl PyPauliLindbladMap { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf_borrowed = slf.borrow(); @@ -1810,7 +1810,7 @@ fn coerce_to_map<'py>( value: &Bound<'py, PyAny>, ) -> PyResult>> { let py = value.py(); - if let Ok(obs) = value.downcast_exact::() { + if let Ok(obs) = value.cast_exact::() { return Ok(Some(obs.clone())); } match PyPauliLindbladMap::py_new(value, None) { diff --git a/crates/quantum_info/src/pauli_lindblad_map/phased_qubit_sparse_pauli.rs b/crates/quantum_info/src/pauli_lindblad_map/phased_qubit_sparse_pauli.rs index 006d77ba981a..aa14bcb2f171 100644 --- a/crates/quantum_info/src/pauli_lindblad_map/phased_qubit_sparse_pauli.rs +++ b/crates/quantum_info/src/pauli_lindblad_map/phased_qubit_sparse_pauli.rs @@ -800,7 +800,7 @@ impl PyPhasedQubitSparsePauli { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf = slf.borrow(); @@ -1039,7 +1039,7 @@ impl PyPhasedQubitSparsePauliList { } return Self::from_label(&label); } - if let Ok(pauli_list) = data.downcast_exact::() { + if let Ok(pauli_list) = data.cast_exact::() { check_num_qubits(data)?; let borrowed = pauli_list.borrow(); let inner = borrowed.inner.read().map_err(|_| InnerReadError)?; @@ -1059,7 +1059,7 @@ impl PyPhasedQubitSparsePauliList { }; return Self::from_sparse_list(vec, num_qubits); } - if let Ok(term) = data.downcast_exact::() { + if let Ok(term) = data.cast_exact::() { return term.borrow().to_phased_qubit_sparse_pauli_list(); }; if let Ok(pauli_list) = Self::from_phased_qubit_sparse_paulis(data, num_qubits) { @@ -1274,14 +1274,12 @@ impl PyPhasedQubitSparsePauliList { "cannot construct an empty PhasedQubitSparsePauliList without knowing `num_qubits`", )); }; - let py_term = first?.downcast::()?.borrow(); + let py_term = first?.cast::()?.borrow(); py_term.inner.to_phased_qubit_sparse_pauli_list() } }; for bound_py_term in iter { - let py_term = bound_py_term? - .downcast::()? - .borrow(); + let py_term = bound_py_term?.cast::()?.borrow(); inner.add_phased_qubit_sparse_pauli(py_term.inner.view())?; } Ok(inner.into()) @@ -1537,7 +1535,7 @@ impl PyPhasedQubitSparsePauliList { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf_borrowed = slf.borrow(); diff --git a/crates/quantum_info/src/pauli_lindblad_map/qubit_sparse_pauli.rs b/crates/quantum_info/src/pauli_lindblad_map/qubit_sparse_pauli.rs index cdb18e56558a..4be809f6d5e8 100644 --- a/crates/quantum_info/src/pauli_lindblad_map/qubit_sparse_pauli.rs +++ b/crates/quantum_info/src/pauli_lindblad_map/qubit_sparse_pauli.rs @@ -968,7 +968,7 @@ fn make_py_pauli(py: Python) -> PyResult> { .getattr("property")? .call1((wrap_pyfunction!(pauli_label, py)?,))?; obj.setattr("label", label_property)?; - Ok(obj.downcast_into::()?.unbind()) + Ok(obj.cast_into::()?.unbind()) } // Return the relevant value from the Python-space sister enumeration. These are Python-space @@ -1005,8 +1005,10 @@ impl<'py> IntoPyObject<'py> for Pauli { } } -impl<'py> FromPyObject<'py> for Pauli { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Pauli { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let value = ob .extract::() .map_err(|_| match ob.get_type().repr() { @@ -1470,7 +1472,7 @@ impl PyQubitSparsePauli { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf = slf.borrow(); @@ -1705,7 +1707,7 @@ impl PyQubitSparsePauliList { } return Self::from_label(&label).map_err(PyErr::from); } - if let Ok(pauli_list) = data.downcast_exact::() { + if let Ok(pauli_list) = data.cast_exact::() { check_num_qubits(data)?; let borrowed = pauli_list.borrow(); let inner = borrowed.inner.read().map_err(|_| InnerReadError)?; @@ -1725,7 +1727,7 @@ impl PyQubitSparsePauliList { }; return Self::from_sparse_list(vec, num_qubits); } - if let Ok(term) = data.downcast_exact::() { + if let Ok(term) = data.cast_exact::() { return term.borrow().to_qubit_sparse_pauli_list(); }; if let Ok(pauli_list) = Self::from_qubit_sparse_paulis(data, num_qubits) { @@ -1958,12 +1960,12 @@ impl PyQubitSparsePauliList { "cannot construct an empty QubitSparsePauliList without knowing `num_qubits`", )); }; - let py_term = first?.downcast::()?.borrow(); + let py_term = first?.cast::()?.borrow(); py_term.inner.to_qubit_sparse_pauli_list() } }; for bound_py_term in iter { - let py_term = bound_py_term?.downcast::()?.borrow(); + let py_term = bound_py_term?.cast::()?.borrow(); inner.add_qubit_sparse_pauli(py_term.inner.view())?; } Ok(inner.into()) @@ -2208,7 +2210,7 @@ impl PyQubitSparsePauliList { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf_borrowed = slf.borrow(); diff --git a/crates/quantum_info/src/sparse_observable/mod.rs b/crates/quantum_info/src/sparse_observable/mod.rs index e99db16f9f9b..4cd02bf3fa14 100644 --- a/crates/quantum_info/src/sparse_observable/mod.rs +++ b/crates/quantum_info/src/sparse_observable/mod.rs @@ -1715,7 +1715,7 @@ fn make_py_bit_term(py: Python) -> PyResult> { .getattr("property")? .call1((wrap_pyfunction!(bit_term_label, py)?,))?; obj.setattr("label", label_property)?; - Ok(obj.downcast_into::()?.unbind()) + Ok(obj.cast_into::()?.unbind()) } // Return the relevant value from the Python-space sister enumeration. These are Python-space @@ -1752,8 +1752,10 @@ impl<'py> IntoPyObject<'py> for BitTerm { } } -impl<'py> FromPyObject<'py> for BitTerm { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for BitTerm { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let value = ob .extract::() .map_err(|_| match ob.get_type().repr() { @@ -1846,7 +1848,7 @@ impl PySparseTerm { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf = slf.borrow(); @@ -2454,7 +2456,7 @@ impl PySparseObservable { } return Self::from_label(&label).map_err(PyErr::from); } - if let Ok(observable) = data.downcast_exact::() { + if let Ok(observable) = data.cast_exact::() { check_num_qubits(data)?; let borrowed = observable.borrow(); let inner = borrowed.inner.read().map_err(|_| InnerReadError)?; @@ -2474,7 +2476,7 @@ impl PySparseObservable { }; return Self::from_sparse_list(vec, num_qubits); } - if let Ok(term) = data.downcast_exact::() { + if let Ok(term) = data.cast_exact::() { return term.borrow().to_observable(); }; if let Ok(observable) = Self::from_terms(data, num_qubits) { @@ -3061,12 +3063,12 @@ impl PySparseObservable { "cannot construct an observable from an empty list without knowing `num_qubits`", )); }; - let py_term = first?.downcast::()?.borrow(); + let py_term = first?.cast::()?.borrow(); py_term.inner.to_observable() } }; for bound_py_term in iter { - let py_term = bound_py_term?.downcast::()?.borrow(); + let py_term = bound_py_term?.cast::()?.borrow(); inner.add_term(py_term.inner.view())?; } Ok(inner.into()) @@ -3622,7 +3624,7 @@ impl PySparseObservable { if slf.is(&other) { return Ok(true); } - let Ok(other) = other.downcast_into::() else { + let Ok(other) = other.cast_into::() else { return Ok(false); }; let slf_borrowed = slf.borrow(); @@ -4008,19 +4010,22 @@ impl ArrayView { /// This allows broadcasting a single item into many locations in a slice (like Numpy), but /// otherwise requires that the index and values are the same length (unlike Python's /// `list`) because that would change the length. - fn set_in_slice<'py, T, S>( + fn set_in_slice<'a, 'py, T, S>( slice: &mut [T], index: PySequenceIndex<'py>, - values: &Bound<'py, PyAny>, + values: Borrowed<'a, 'py, PyAny>, ) -> PyResult<()> where T: Copy + TryFrom, - S: FromPyObject<'py>, + S: for<'b> FromPyObject<'b, 'py, Error: Into>, PyErr: From<>::Error>, { match index.with_len(slice.len())? { SequenceIndex::Int(index) => { - slice[index] = values.extract::()?.try_into()?; + slice[index] = values + .extract::() + .map_err(Into::::into)? + .try_into()?; Ok(()) } indices => { @@ -4032,7 +4037,13 @@ impl ArrayView { } else { let values = values .try_iter()? - .map(|value| value?.extract::()?.try_into().map_err(PyErr::from)) + .map(|value| { + value? + .extract::() + .map_err(Into::::into)? + .try_into() + .map_err(PyErr::from) + }) .collect::>>()?; if indices.len() != values.len() { return Err(PyValueError::new_err(format!( @@ -4051,6 +4062,7 @@ impl ArrayView { } let mut obs = self.base.write().map_err(|_| InnerWriteError)?; + let values = values.as_borrowed(); match self.slot { ArraySlot::Coeffs => set_in_slice::<_, Complex64>(obs.coeffs_mut(), index, values), ArraySlot::BitTerms => set_in_slice::(obs.bit_terms_mut(), index, values), @@ -4151,7 +4163,7 @@ fn coerce_to_observable<'py>( value: &Bound<'py, PyAny>, ) -> PyResult>> { let py = value.py(); - if let Ok(obs) = value.downcast_exact::() { + if let Ok(obs) = value.cast_exact::() { return Ok(Some(obs.clone())); } match PySparseObservable::py_new(value, None) { diff --git a/crates/synthesis/src/evolution/pauli_network.rs b/crates/synthesis/src/evolution/pauli_network.rs index 79d6df2cf2f3..721cc52865bd 100644 --- a/crates/synthesis/src/evolution/pauli_network.rs +++ b/crates/synthesis/src/evolution/pauli_network.rs @@ -314,9 +314,9 @@ pub fn pauli_network_synthesis_inner( // go over the input pauli network and extract a list of pauli rotations and // the corresponding rotation angles for item in pauli_network { - let tuple = item.downcast::()?; + let tuple = item.cast::()?; - let sparse_pauli: String = tuple.get_item(0)?.downcast::()?.extract()?; + let sparse_pauli: String = tuple.get_item(0)?.cast::()?.extract()?; let qubits: Vec = tuple.get_item(1)?.extract()?; let angle: Param = tuple.get_item(2)?.extract()?; diff --git a/crates/transpiler/src/angle_bound_registry.rs b/crates/transpiler/src/angle_bound_registry.rs index 7daaca9cfc79..b04edfa2609a 100644 --- a/crates/transpiler/src/angle_bound_registry.rs +++ b/crates/transpiler/src/angle_bound_registry.rs @@ -32,7 +32,13 @@ impl CallbackType { match self { Self::Python(inner) => { let qubits: Vec = qubits.iter().map(|x| x.index()).collect(); - Python::attach(|py| inner.bind(py).call1((angles, qubits))?.extract()) + Python::attach(|py| { + inner + .bind(py) + .call1((angles, qubits))? + .extract() + .map_err(PyErr::from) + }) } Self::Native(inner) => Ok(inner(angles, qubits)), } diff --git a/crates/transpiler/src/commutation_checker.rs b/crates/transpiler/src/commutation_checker.rs index fd860c9fbe9c..45a0bd5cd1c9 100644 --- a/crates/transpiler/src/commutation_checker.rs +++ b/crates/transpiler/src/commutation_checker.rs @@ -261,7 +261,7 @@ impl CommutationChecker { } fn __setstate__(&mut self, py: Python, state: Py) -> PyResult<()> { - let dict_state = state.downcast_bound::(py)?; + let dict_state = state.cast_bound::(py)?; self.cache_max_entries = dict_state .get_item("cache_max_entries")? .unwrap() @@ -276,7 +276,7 @@ impl CommutationChecker { let raw_cache: Bound = dict_state.get_item("cache")?.unwrap().extract()?; self.cache = HashMap::with_capacity(raw_cache.len()); for (key, value) in raw_cache.iter() { - let value_dict: &Bound = value.downcast()?; + let value_dict: &Bound = value.cast()?; self.cache.insert( key.extract()?, commutation_cache_entry_from_pydict(value_dict)?, @@ -814,14 +814,16 @@ impl<'py> IntoPyObject<'py> for CommutationLibraryEntry { } } -impl<'py> FromPyObject<'py> for CommutationLibraryEntry { - fn extract_bound(b: &Bound<'py, PyAny>) -> Result { +impl<'a, 'py> FromPyObject<'a, 'py> for CommutationLibraryEntry { + type Error = PyErr; + + fn extract(b: Borrowed<'a, 'py, PyAny>) -> Result { if let Ok(b) = b.extract::() { return Ok(CommutationLibraryEntry::Commutes(b)); } - let dict = b.downcast::()?; + let dict = b.cast::()?; let mut ret = hashbrown::HashMap::with_capacity(dict.len()); - for (k, v) in dict { + for (k, v) in &*dict { let raw_key: SmallVec<[Option; 2]> = k.extract()?; let v: bool = v.extract()?; let key = raw_key.into_iter().map(|key| key.map(Qubit)).collect(); diff --git a/crates/transpiler/src/equivalence.rs b/crates/transpiler/src/equivalence.rs index 96684049361d..41a678f334e8 100644 --- a/crates/transpiler/src/equivalence.rs +++ b/crates/transpiler/src/equivalence.rs @@ -47,8 +47,8 @@ use qiskit_circuit::packed_instruction::PackedOperation; use crate::standard_equivalence_library::generate_standard_equivalence_library; mod exceptions { - use pyo3::import_exception_bound; - import_exception_bound! {qiskit.circuit.exceptions, CircuitError} + use pyo3::import_exception; + import_exception! {qiskit.circuit.exceptions, CircuitError} } pub static PYDIGRAPH: ImportOnceCell = ImportOnceCell::new("rustworkx", "PyDiGraph"); @@ -293,8 +293,10 @@ pub struct GateOper { params: SmallVec<[Param; 3]>, } -impl<'py> FromPyObject<'py> for GateOper { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for GateOper { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let op_struct: OperationFromPython = ob.extract()?; Ok(Self { operation: op_struct.operation, @@ -328,11 +330,13 @@ impl<'py> IntoPyObject<'py> for CircuitFromPython { } } -impl FromPyObject<'_> for CircuitFromPython { - fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for CircuitFromPython { + type Error = PyErr; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { if ob.is_instance(QUANTUM_CIRCUIT.get_bound(ob.py()))? { let data: Bound = ob.getattr("_data")?; - let data_downcast: Bound = data.downcast_into()?; + let data_downcast: Bound = data.cast_into()?; let data_extract: CircuitData = data_downcast.extract()?; Ok(Self(data_extract)) } else { @@ -567,9 +571,9 @@ impl EquivalenceLibrary { fn __setstate__(mut slf: PyRefMut, state: &Bound) -> PyResult<()> { slf.rule_id = state.get_item("rule_id")?.unwrap().extract()?; let graph_nodes_ref: Bound = state.get_item("graph_nodes")?.unwrap(); - let graph_nodes: &Bound = graph_nodes_ref.downcast()?; + let graph_nodes: &Bound = graph_nodes_ref.cast()?; let graph_edge_ref: Bound = state.get_item("graph_edges")?.unwrap(); - let graph_edges: &Bound = graph_edge_ref.downcast()?; + let graph_edges: &Bound = graph_edge_ref.cast()?; slf.graph = GraphType::new(); for node_weight in graph_nodes { slf.graph.add_node(node_weight.extract()?); diff --git a/crates/transpiler/src/lib.rs b/crates/transpiler/src/lib.rs index 4d8d4cd2b854..a50aa5eb101c 100644 --- a/crates/transpiler/src/lib.rs +++ b/crates/transpiler/src/lib.rs @@ -26,7 +26,7 @@ pub use transpiler::transpile; mod gate_metrics; -use pyo3::import_exception_bound; +use pyo3::import_exception; -import_exception_bound! {qiskit.exceptions, QiskitError} -import_exception_bound! {qiskit.transpiler.exceptions, TranspilerError} +import_exception! {qiskit.exceptions, QiskitError} +import_exception! {qiskit.transpiler.exceptions, TranspilerError} diff --git a/crates/transpiler/src/passes/alap_schedule_analysis.rs b/crates/transpiler/src/passes/alap_schedule_analysis.rs index f99377889c48..b2bed5e4b23c 100644 --- a/crates/transpiler/src/passes/alap_schedule_analysis.rs +++ b/crates/transpiler/src/passes/alap_schedule_analysis.rs @@ -199,7 +199,7 @@ pub fn py_run_alap_schedule_analysis( let mut op_durations = HashMap::new(); for (py_node, py_duration) in node_durations.iter() { let node_idx = py_node - .downcast_into::()? + .cast_into::()? .extract::()? .node .expect("Node index not found."); @@ -217,7 +217,7 @@ pub fn py_run_alap_schedule_analysis( let mut op_durations = HashMap::new(); for (py_node, py_duration) in node_durations.iter() { let node_idx = py_node - .downcast_into::()? + .cast_into::()? .extract::()? .node .expect("Node index not found."); diff --git a/crates/transpiler/src/passes/asap_schedule_analysis.rs b/crates/transpiler/src/passes/asap_schedule_analysis.rs index df53176c0b72..d4b0789f5e37 100644 --- a/crates/transpiler/src/passes/asap_schedule_analysis.rs +++ b/crates/transpiler/src/passes/asap_schedule_analysis.rs @@ -176,7 +176,7 @@ pub fn py_run_asap_schedule_analysis( let mut op_durations = HashMap::new(); for (py_node, py_duration) in node_durations.iter() { let node_idx = py_node - .downcast_into::()? + .cast_into::()? .extract::()? .node .expect("Node index not found."); @@ -194,7 +194,7 @@ pub fn py_run_asap_schedule_analysis( let mut op_durations = HashMap::new(); for (py_node, py_duration) in node_durations.iter() { let node_idx = py_node - .downcast_into::()? + .cast_into::()? .extract::()? .node .expect("Node index not found."); diff --git a/crates/transpiler/src/passes/check_map.rs b/crates/transpiler/src/passes/check_map.rs index e64145c1eae2..43a6ffd9dbbb 100644 --- a/crates/transpiler/src/passes/check_map.rs +++ b/crates/transpiler/src/passes/check_map.rs @@ -56,7 +56,7 @@ fn recurse( let block_obj = raw_block?; let block = block_obj .getattr(intern!(py, "_data"))? - .downcast::()? + .cast::()? .borrow(); let new_dag: DAGCircuit = circuit_to_dag.call1((block_obj.clone(),))?.extract()?; diff --git a/crates/transpiler/src/passes/disjoint_layout.rs b/crates/transpiler/src/passes/disjoint_layout.rs index 3f2193776f0c..8d5ba20a782d 100644 --- a/crates/transpiler/src/passes/disjoint_layout.rs +++ b/crates/transpiler/src/passes/disjoint_layout.rs @@ -365,7 +365,7 @@ fn build_interaction_graph( unreachable!("Control flow must be a python instruction"); }; let raw_blocks = py_inst.instruction.getattr(py, "blocks").unwrap(); - let blocks: &Bound = raw_blocks.downcast_bound::(py).unwrap(); + let blocks: &Bound = raw_blocks.cast_bound::(py).unwrap(); for block in blocks.iter() { let mut inner_wire_map = vec![Qubit(u32::MAX); wire_map.len()]; let node_qargs = dag.get_qargs(inst.qubits); diff --git a/crates/transpiler/src/passes/high_level_synthesis.rs b/crates/transpiler/src/passes/high_level_synthesis.rs index d5645d743355..473372e10eee 100644 --- a/crates/transpiler/src/passes/high_level_synthesis.rs +++ b/crates/transpiler/src/passes/high_level_synthesis.rs @@ -591,7 +591,7 @@ fn run_on_circuitdata( // old_blocks_py keeps the original QuantumCircuit's appearing within control-flow ops // new_blocks_py keeps the recursively synthesized circuits let old_blocks_py = old_blocks_as_bound_obj.getattr(intern!(py, "blocks"))?; - let old_blocks_py = old_blocks_py.downcast::()?; + let old_blocks_py = old_blocks_py.cast::()?; let mut new_blocks_py: Vec> = Vec::with_capacity(old_blocks_py.len()); // We do not allow using any additional qubits outside of the block. diff --git a/crates/transpiler/src/passes/sabre/dag.rs b/crates/transpiler/src/passes/sabre/dag.rs index c0f62fc3563e..7725089a4860 100644 --- a/crates/transpiler/src/passes/sabre/dag.rs +++ b/crates/transpiler/src/passes/sabre/dag.rs @@ -33,7 +33,7 @@ fn control_flow_block_dags<'a>( .instruction .bind(py) .getattr("blocks")? - .downcast::()? + .cast::()? .iter() .map(move |block| circuit_to_dag(block.extract()?, false, None, None))) } diff --git a/crates/transpiler/src/passes/unitary_synthesis.rs b/crates/transpiler/src/passes/unitary_synthesis.rs index ac4fff10bcbf..f8c3d8ef2f5a 100644 --- a/crates/transpiler/src/passes/unitary_synthesis.rs +++ b/crates/transpiler/src/passes/unitary_synthesis.rs @@ -30,7 +30,7 @@ use pyo3::prelude::*; use pyo3::types::{IntoPyDict, PyDict, PyString, PyType}; use pyo3::wrap_pyfunction; -use qiskit_circuit::converters::{QuantumCircuitData, circuit_to_dag}; +use qiskit_circuit::converters::circuit_to_dag; use qiskit_circuit::dag_circuit::{DAGCircuit, DAGCircuitBuilder, NodeType}; use qiskit_circuit::operations::{Operation, OperationRef, Param, PythonOperation, StandardGate}; use qiskit_circuit::packed_instruction::{PackedInstruction, PackedOperation}; @@ -319,12 +319,7 @@ pub fn run_unitary_synthesis( .map(|qarg| qubit_indices[qarg.0 as usize]) .collect_vec(); let res = run_unitary_synthesis( - &mut circuit_to_dag( - QuantumCircuitData::extract_bound(&raw_block?)?, - false, - None, - None, - )?, + &mut circuit_to_dag(raw_block?.extract()?, false, None, None)?, new_ids, min_qubits, target, @@ -684,7 +679,7 @@ fn get_2q_decomposers_from_target( let py_type = module.getattr("type")?; Ok(py_type .call1((gate.clone().into_pyobject(py)?,))? - .downcast_into::()? + .cast_into::()? .unbind()) })?; RXXEquivalent::CustomPython(gate_type) diff --git a/crates/transpiler/src/passes/vf2/vf2_layout.rs b/crates/transpiler/src/passes/vf2/vf2_layout.rs index d64d3869bd41..91476b463c24 100644 --- a/crates/transpiler/src/passes/vf2/vf2_layout.rs +++ b/crates/transpiler/src/passes/vf2/vf2_layout.rs @@ -361,7 +361,7 @@ impl VirtualInteractions { }; let wire_map: Vec<_> = qubits.iter().map(|i| wire_map[i.index()]).collect(); let blocks = py_inst.instruction.bind(py).getattr("blocks")?; - for block in blocks.downcast::()?.iter() { + for block in blocks.cast::()?.iter() { if !self.add_interactions_from( &circuit_to_dag(block.extract()?, false, None, None)?, &wire_map, diff --git a/crates/transpiler/src/target/mod.rs b/crates/transpiler/src/target/mod.rs index d87a29a8455b..9b3889ddd8cd 100644 --- a/crates/transpiler/src/target/mod.rs +++ b/crates/transpiler/src/target/mod.rs @@ -159,13 +159,15 @@ impl<'a, 'py> IntoPyObject<'py> for &'a NormalOperation { } } -impl<'py> FromPyObject<'py> for NormalOperation { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for NormalOperation { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let operation: OperationFromPython = ob.extract()?; Ok(Self { operation: operation.operation, params: operation.params, - op_object: Ok(ob.clone().unbind()).into(), + op_object: Ok(ob.to_owned().unbind()).into(), }) } } @@ -908,7 +910,7 @@ impl Target { .extract::)>>()?, ); let angle_bounds_raw = state.get_item("angle_bounds")?.unwrap(); - let angle_bounds_dict = angle_bounds_raw.downcast::()?; + let angle_bounds_dict = angle_bounds_raw.cast::()?; type AngleBoundIterList = Vec<(String, SmallVec<[Option<[f64; 2]>; 3]>)>; let angle_bounds_list: AngleBoundIterList = angle_bounds_dict.items().extract()?; for (gate, bounds) in angle_bounds_list { diff --git a/crates/transpiler/src/target/qargs.rs b/crates/transpiler/src/target/qargs.rs index b9c32dab38f0..95b304be991e 100644 --- a/crates/transpiler/src/target/qargs.rs +++ b/crates/transpiler/src/target/qargs.rs @@ -99,8 +99,10 @@ impl<'py> IntoPyObject<'py> for &Qargs { } } -impl<'py> FromPyObject<'py> for Qargs { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'a, 'py> FromPyObject<'a, 'py> for Qargs { + type Error = >::Error; + + fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let qargs: Option = ob.extract()?; match qargs { Some(qargs) => Ok(Self::Concrete(qargs)), diff --git a/crates/transpiler/src/transpile_layout.rs b/crates/transpiler/src/transpile_layout.rs index d701fb0ff992..49c405a5c5e5 100644 --- a/crates/transpiler/src/transpile_layout.rs +++ b/crates/transpiler/src/transpile_layout.rs @@ -543,7 +543,7 @@ impl TranspileLayout { }; let index_map = py_layout .getattr(intern!(py, "input_qubit_mapping"))? - .downcast::()? + .cast::()? .iter() .map(|(k, v)| -> PyResult<(usize, ShareableQubit)> { let index: usize = v.extract()?; @@ -567,9 +567,9 @@ impl TranspileLayout { let input_registers: Vec = py_layout .getattr(intern!(py, "initial_layout"))? .call_method0(intern!(py, "get_registers"))? - .downcast::()? + .cast::()? .iter() - .map(|x| x.extract::()) + .map(|x| x.extract::().map_err(PyErr::from)) .collect::>>()?; Ok(Self::new( initial_layout,