From fe0bb69c83ff105555e5087810bad042db984491 Mon Sep 17 00:00:00 2001 From: Kevin Hartman Date: Tue, 2 Apr 2024 14:38:19 -0400 Subject: [PATCH] Resolve qasm3 warnings. --- crates/qasm3/src/build.rs | 4 +-- crates/qasm3/src/circuit.rs | 65 ++++++++++++++++++++----------------- crates/qasm3/src/expr.rs | 17 ++++++---- crates/qasm3/src/lib.rs | 53 +++++++++++++++++------------- 4 files changed, 77 insertions(+), 62 deletions(-) diff --git a/crates/qasm3/src/build.rs b/crates/qasm3/src/build.rs index cc80aa4f762d..154cd391252a 100644 --- a/crates/qasm3/src/build.rs +++ b/crates/qasm3/src/build.rs @@ -143,7 +143,7 @@ impl BuilderState { let gate = self.symbols.gates.get(gate_id).ok_or_else(|| { QASM3ImporterError::new_err(format!("internal error: unknown gate {:?}", gate_id)) })?; - let params = PyTuple::new( + let params = PyTuple::new_bound( py, call.params() .as_ref() @@ -206,7 +206,7 @@ impl BuilderState { } } } - PyTuple::new(py, qubits.values()) + PyTuple::new_bound(py, qubits.values()) } else { // If there's no qargs (represented in the ASG with a `None` rather than an empty // vector), it's a barrier over all in-scope qubits, which is all qubits, unless we're diff --git a/crates/qasm3/src/circuit.rs b/crates/qasm3/src/circuit.rs index a2c39e754023..1293b22580b0 100644 --- a/crates/qasm3/src/circuit.rs +++ b/crates/qasm3/src/circuit.rs @@ -22,7 +22,7 @@ pub trait PyRegister { // or at a minimum // fn iter<'a>(&'a self, py: Python<'a>) -> ::pyo3::types::iter::PyListIterator<'a>; // but we can't use the former before Rust 1.75 and the latter before PyO3 0.21. - fn bit_list<'a>(&'a self, py: Python<'a>) -> &'a PyList; + fn bit_list<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyList>; } macro_rules! register_type { @@ -43,13 +43,13 @@ macro_rules! register_type { fn bit(&self, py: Python, index: usize) -> PyResult> { // Unfortunately, `PyList::get_item_unchecked` isn't usable with the stable ABI. self.items - .as_ref(py) + .bind(py) .get_item(index) .map(|item| item.into_py(py)) } - fn bit_list<'a>(&'a self, py: Python<'a>) -> &'a PyList { - self.items.as_ref(py) + fn bit_list<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyList> { + self.items.bind(py) } } @@ -106,9 +106,9 @@ impl PyGate { A: IntoPy>, { let args = args.into_py(py); - let received_num_params = args.as_ref(py).len(); + let received_num_params = args.bind(py).len(); if received_num_params == self.num_params { - self.constructor.call1(py, args.as_ref(py)) + self.constructor.call1(py, args.bind(py)) } else { Err(QASM3ImporterError::new_err(format!( "internal error: wrong number of params for {} (got {}, expected {})", @@ -143,11 +143,11 @@ impl PyGate { } } - fn __repr__<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> { - PyString::new(py, "CustomGate(name={!r}, num_params={}, num_qubits={})").call_method1( + fn __repr__<'py>(&self, py: Python<'py>) -> PyResult> { + PyString::new_bound(py, "CustomGate(name={!r}, num_params={}, num_qubits={})").call_method1( "format", ( - PyString::new(py, &self.name), + PyString::new_bound(py, &self.name), self.num_params, self.num_qubits, ), @@ -156,7 +156,7 @@ impl PyGate { fn __reduce__(&self, py: Python) -> Py { ( - PyType::new::(py), + PyType::new_bound::(py), ( self.constructor.clone_ref(py), &self.name, @@ -188,27 +188,30 @@ pub struct PyCircuitModule { impl PyCircuitModule { /// Import the necessary components from `qiskit.circuit`. pub fn import(py: Python) -> PyResult { - let module = PyModule::import(py, "qiskit.circuit")?; + let module = PyModule::import_bound(py, "qiskit.circuit")?; Ok(Self { circuit: module .getattr("QuantumCircuit")? - .downcast::()? - .into_py(py), + .downcast_into::()? + .unbind(), qreg: module .getattr("QuantumRegister")? - .downcast::()? - .into_py(py), - qubit: module.getattr("Qubit")?.downcast::()?.into_py(py), + .downcast_into::()? + .unbind(), + qubit: module.getattr("Qubit")?.downcast_into::()?.unbind(), creg: module .getattr("ClassicalRegister")? - .downcast::()? - .into_py(py), - clbit: module.getattr("Clbit")?.downcast::()?.into_py(py), + .downcast_into::()? + .unbind(), + clbit: module.getattr("Clbit")?.downcast_into::()?.unbind(), circuit_instruction: module .getattr("CircuitInstruction")? - .downcast::()? - .into_py(py), - barrier: module.getattr("Barrier")?.downcast::()?.into_py(py), + .downcast_into::()? + .unbind(), + barrier: module + .getattr("Barrier")? + .downcast_into::()? + .unbind(), // Measure is a singleton, so just store the object. measure: module.getattr("Measure")?.call0()?.into_py(py), }) @@ -227,9 +230,10 @@ impl PyCircuitModule { let qreg = self.qreg.call1(py, (size, name.into_py(py)))?; Ok(PyQuantumRegister { items: qreg - .getattr(py, "_bits")? - .downcast::(py)? - .into_py(py), + .bind(py) + .getattr("_bits")? + .downcast_into::()? + .unbind(), object: qreg, }) } @@ -247,9 +251,10 @@ impl PyCircuitModule { let creg = self.creg.call1(py, (size, name.into_py(py)))?; Ok(PyClassicalRegister { items: creg - .getattr(py, "_bits")? - .downcast::(py)? - .into_py(py), + .bind(py) + .getattr("_bits")? + .downcast_into::()? + .unbind(), object: creg, }) } @@ -291,8 +296,8 @@ pub struct PyCircuit(Py); impl PyCircuit { /// Untyped access to the inner Python object. - pub fn inner<'a>(&'a self, py: Python<'a>) -> &'a PyAny { - self.0.as_ref(py) + pub fn inner<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyAny> { + self.0.bind(py) } pub fn add_qreg(&self, py: Python, qreg: &PyQuantumRegister) -> PyResult<()> { diff --git a/crates/qasm3/src/expr.rs b/crates/qasm3/src/expr.rs index 8fc4c8a8a534..d16bd53add05 100644 --- a/crates/qasm3/src/expr.rs +++ b/crates/qasm3/src/expr.rs @@ -110,7 +110,7 @@ struct BroadcastQubitsIter<'py> { } impl<'py> Iterator for BroadcastQubitsIter<'py> { - type Item = &'py PyTuple; + type Item = Bound<'py, PyTuple>; fn next(&mut self) -> Option { if self.offset >= self.len { @@ -122,7 +122,10 @@ impl<'py> Iterator for BroadcastQubitsIter<'py> { BroadcastItem::Register(bits) => bits[offset].clone_ref(self.py), }; self.offset += 1; - Some(PyTuple::new(self.py, self.items.iter().map(to_scalar))) + Some(PyTuple::new_bound( + self.py, + self.items.iter().map(to_scalar), + )) } fn size_hint(&self) -> (usize, Option) { @@ -140,7 +143,7 @@ struct BroadcastMeasureIter<'a, 'py> { } impl<'a, 'py> Iterator for BroadcastMeasureIter<'a, 'py> { - type Item = (&'py PyTuple, &'py PyTuple); + type Item = (Bound<'py, PyTuple>, Bound<'py, PyTuple>); fn next(&mut self) -> Option { if self.offset >= self.len { @@ -153,8 +156,8 @@ impl<'a, 'py> Iterator for BroadcastMeasureIter<'a, 'py> { }; self.offset += 1; Some(( - PyTuple::new(self.py, &[to_scalar(self.qarg)]), - PyTuple::new(self.py, &[to_scalar(self.carg)]), + PyTuple::new_bound(self.py, &[to_scalar(self.qarg)]), + PyTuple::new_bound(self.py, &[to_scalar(self.carg)]), )) } @@ -321,7 +324,7 @@ pub fn broadcast_qubits<'a, 'py, T>( our_symbols: &PySymbolTable, ast_symbols: &SymbolTable, qargs: T, -) -> PyResult> +) -> PyResult>> where T: IntoIterator + 'a, { @@ -358,7 +361,7 @@ pub fn broadcast_measure<'a, 'py>( py: Python<'py>, qarg: &'a BroadcastItem, carg: &'a BroadcastItem, -) -> PyResult + 'a> +) -> PyResult, Bound<'py, PyTuple>)> + 'a> where 'py: 'a, { diff --git a/crates/qasm3/src/lib.rs b/crates/qasm3/src/lib.rs index 0db8317ba6a1..776724598d4b 100644 --- a/crates/qasm3/src/lib.rs +++ b/crates/qasm3/src/lib.rs @@ -16,6 +16,7 @@ mod error; mod expr; use std::ffi::OsString; +use std::ops::Deref; use std::path::{Path, PathBuf}; use hashbrown::HashMap; @@ -24,6 +25,7 @@ use pyo3::prelude::*; use pyo3::types::{PyModule, PyTuple}; use oq3_semantics::syntax_to_semantics::parse_source_string; +use pyo3::pybacked::PyBackedStr; use crate::error::QASM3ImporterError; @@ -58,14 +60,15 @@ const STDGATES_INC_CUSTOM_GATES_ATTR: &str = "STDGATES_INC_GATES"; #[pyfunction] #[pyo3(pass_module, signature = (source, /, *, custom_gates=None, include_path=None))] pub fn loads( - module: &PyModule, + module: Bound, py: Python, source: String, custom_gates: Option>, include_path: Option>, ) -> PyResult { let default_include_path = || -> PyResult> { - Ok(vec![Path::new(module.filename()?) + let filename: PyBackedStr = module.filename()?.try_into()?; + Ok(vec![Path::new(filename.deref()) .parent() .unwrap() .join(["qasm", "libs", "dummy"].iter().collect::()) @@ -130,34 +133,35 @@ pub fn loads( signature = (pathlike_or_filelike, /, *, custom_gates=None, include_path=None), )] pub fn load( - module: &PyModule, + module: Bound, py: Python, - pathlike_or_filelike: &PyAny, + pathlike_or_filelike: Bound, custom_gates: Option>, include_path: Option>, ) -> PyResult { - let source = - if pathlike_or_filelike.is_instance(PyModule::import(py, "io")?.getattr("TextIOBase")?)? { - pathlike_or_filelike - .call_method0("read")? - .extract::()? - } else { - let path = PyModule::import(py, "os")? - .getattr("fspath")? - .call1((pathlike_or_filelike,))? - .extract::()?; - ::std::fs::read_to_string(&path).map_err(|err| { - QASM3ImporterError::new_err(format!("failed to read file '{:?}': {:?}", &path, err)) - })? - }; + let source = if pathlike_or_filelike + .is_instance(&PyModule::import_bound(py, "io")?.getattr("TextIOBase")?)? + { + pathlike_or_filelike + .call_method0("read")? + .extract::()? + } else { + let path = PyModule::import_bound(py, "os")? + .getattr("fspath")? + .call1((pathlike_or_filelike,))? + .extract::()?; + ::std::fs::read_to_string(&path).map_err(|err| { + QASM3ImporterError::new_err(format!("failed to read file '{:?}': {:?}", &path, err)) + })? + }; loads(module, py, source, custom_gates, include_path) } /// Create a suitable sequence for use with the ``custom_gates`` of :func:`load` and :func:`loads`, /// as a Python object on the Python heap, so we can re-use it, and potentially expose it has a /// data attribute to users. -fn stdgates_inc_gates(py: Python) -> PyResult<&PyTuple> { - let library = PyModule::import(py, "qiskit.circuit.library")?; +fn stdgates_inc_gates(py: Python) -> PyResult> { + let library = PyModule::import_bound(py, "qiskit.circuit.library")?; let stdlib_gate = |qiskit_class, name, num_params, num_qubits| -> PyResult> { Ok(circuit::PyGate::new( py, @@ -168,7 +172,7 @@ fn stdgates_inc_gates(py: Python) -> PyResult<&PyTuple> { ) .into_py(py)) }; - Ok(PyTuple::new( + Ok(PyTuple::new_bound( py, vec![ stdlib_gate("PhaseGate", "p", 1, 1)?, @@ -210,10 +214,13 @@ fn stdgates_inc_gates(py: Python) -> PyResult<&PyTuple> { /// Internal module supplying the OpenQASM 3 import capabilities. The entries in it should largely /// be re-exposed directly to public Python space. #[pymodule] -fn _qasm3(py: Python<'_>, module: &PyModule) -> PyResult<()> { +fn _qasm3(module: &Bound) -> PyResult<()> { module.add_function(wrap_pyfunction!(loads, module)?)?; module.add_function(wrap_pyfunction!(load, module)?)?; module.add_class::()?; - module.add(STDGATES_INC_CUSTOM_GATES_ATTR, stdgates_inc_gates(py)?)?; + module.add( + STDGATES_INC_CUSTOM_GATES_ATTR, + stdgates_inc_gates(module.py())?, + )?; Ok(()) }