microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
alex/1898

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc_eval/src/lib.rs

2065lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! The Q# evaluator handles the execution of Q# programs and/or fragments.
5//! It operates based on vectors of `ExecGraphNode` instances, which act as a control flow graph
6//! and are generated by lowering to FIR. The evaluator will iterate through the given graph,
7//! executing the instructions it encounters and updating the state it was given accordingly, and using
8//! the FIR store to look up graphs for any called functions or operations. The evaluator handles tracking
9//! of stack frames and push/pop of variable scopes, and uses the index into the current execution graph
10//! as a kind of stack pointer, updating the index based on `Jump`, `JumpIf`, and `JumpIfNot` instructions.
11//!
12//! Of note, the evaluator does not own the program state, which is tracked by the passed in `Env`
13//! and `Backend` instances. This allows the evaluator to be reentrant, and supports both whole-program,
14//! effectively stateless execution (like running shots of a program) stateful execution scenarios
15//! (like debugging or notebooks).
16
17#[cfg(test)]
18mod tests;
19
20pub mod backend;
21pub mod debug;
22mod error;
23mod intrinsic;
24pub mod output;
25pub mod state;
26pub mod val;
27
28use crate::val::{
29 index_array, make_range, slice_array, update_index_range, update_index_single, Value,
30};
31use backend::Backend;
32use debug::{CallStack, Frame};
33pub use error::PackageSpan;
34use miette::Diagnostic;
35use num_bigint::BigInt;
36use output::Receiver;
37use qsc_data_structures::{functors::FunctorApp, index_map::IndexMap, span::Span};
38use qsc_fir::fir::{
39 self, BinOp, CallableImpl, ExecGraph, ExecGraphNode, Expr, ExprId, ExprKind, Field,
40 FieldAssign, Global, Lit, LocalItemId, LocalVarId, PackageId, PackageStoreLookup, PatId,
41 PatKind, PrimField, Res, StmtId, StoreItemId, StringComponent, UnOp,
42};
43use qsc_fir::ty::Ty;
44use qsc_lowerer::map_fir_package_to_hir;
45use rand::{rngs::StdRng, SeedableRng};
46use rustc_hash::{FxHashMap, FxHashSet};
47use std::ops;
48use std::{
49 cell::RefCell,
50 fmt::{self, Display, Formatter},
51 iter,
52 ops::Neg,
53 rc::Rc,
54};
55use thiserror::Error;
56use val::update_functor_app;
57
58#[derive(Clone, Debug, Diagnostic, Error)]
59pub enum Error {
60 #[error("array too large")]
61 #[diagnostic(code("Qsc.Eval.ArrayTooLarge"))]
62 ArrayTooLarge(#[label("this array has too many items")] PackageSpan),
63
64 #[error("callable already counted")]
65 #[diagnostic(help(
66 "counting for a given callable must be stopped before it can be started again"
67 ))]
68 #[diagnostic(code("Qsc.Eval.CallableAlreadyCounted"))]
69 CallableAlreadyCounted(#[label] PackageSpan),
70
71 #[error("callable not counted")]
72 #[diagnostic(help("counting for a given callable must be started before it can be stopped"))]
73 #[diagnostic(code("Qsc.Eval.CallableNotCounted"))]
74 CallableNotCounted(#[label] PackageSpan),
75
76 #[error("invalid array length: {0}")]
77 #[diagnostic(code("Qsc.Eval.InvalidArrayLength"))]
78 InvalidArrayLength(i64, #[label("cannot be used as a length")] PackageSpan),
79
80 #[error("division by zero")]
81 #[diagnostic(code("Qsc.Eval.DivZero"))]
82 DivZero(#[label("cannot divide by zero")] PackageSpan),
83
84 #[error("empty range")]
85 #[diagnostic(code("Qsc.Eval.EmptyRange"))]
86 EmptyRange(#[label("the range cannot be empty")] PackageSpan),
87
88 #[error("value cannot be used as an index: {0}")]
89 #[diagnostic(code("Qsc.Eval.InvalidIndex"))]
90 InvalidIndex(i64, #[label("invalid index")] PackageSpan),
91
92 #[error("integer too large for operation")]
93 #[diagnostic(code("Qsc.Eval.IntTooLarge"))]
94 IntTooLarge(i64, #[label("this value is too large")] PackageSpan),
95
96 #[error("index out of range: {0}")]
97 #[diagnostic(code("Qsc.Eval.IndexOutOfRange"))]
98 IndexOutOfRange(i64, #[label("out of range")] PackageSpan),
99
100 #[error("intrinsic callable `{0}` failed: {1}")]
101 #[diagnostic(code("Qsc.Eval.IntrinsicFail"))]
102 IntrinsicFail(String, String, #[label] PackageSpan),
103
104 #[error("invalid rotation angle: {0}")]
105 #[diagnostic(code("Qsc.Eval.InvalidRotationAngle"))]
106 InvalidRotationAngle(f64, #[label("invalid rotation angle")] PackageSpan),
107
108 #[error("negative integers cannot be used here: {0}")]
109 #[diagnostic(code("Qsc.Eval.InvalidNegativeInt"))]
110 InvalidNegativeInt(i64, #[label("invalid negative integer")] PackageSpan),
111
112 #[error("output failure")]
113 #[diagnostic(code("Qsc.Eval.OutputFail"))]
114 OutputFail(#[label("failed to generate output")] PackageSpan),
115
116 #[error("qubits in invocation are not unique")]
117 #[diagnostic(code("Qsc.Eval.QubitUniqueness"))]
118 QubitUniqueness(#[label] PackageSpan),
119
120 #[error("qubits already counted")]
121 #[diagnostic(help("counting for qubits must be stopped before it can be started again"))]
122 #[diagnostic(code("Qsc.Eval.QubitsAlreadyCounted"))]
123 QubitsAlreadyCounted(#[label] PackageSpan),
124
125 #[error("qubits not counted")]
126 #[diagnostic(help("counting for qubits must be started before it can be stopped"))]
127 #[diagnostic(code("Qsc.Eval.QubitsNotCounted"))]
128 QubitsNotCounted(#[label] PackageSpan),
129
130 #[error("qubits are not separable")]
131 #[diagnostic(help("subset of qubits provided as arguments must not be entangled with any qubits outside of the subset"))]
132 #[diagnostic(code("Qsc.Eval.QubitsNotSeparable"))]
133 QubitsNotSeparable(#[label] PackageSpan),
134
135 #[error("range with step size of zero")]
136 #[diagnostic(code("Qsc.Eval.RangeStepZero"))]
137 RangeStepZero(#[label("invalid range")] PackageSpan),
138
139 #[error("Qubit{0} released while not in |0⟩ state")]
140 #[diagnostic(help("qubits should be returned to the |0⟩ state before being released to satisfy the assumption that allocated qubits start in the |0⟩ state"))]
141 #[diagnostic(code("Qsc.Eval.ReleasedQubitNotZero"))]
142 ReleasedQubitNotZero(usize, #[label("Qubit{0}")] PackageSpan),
143
144 #[error("cannot compare measurement results")]
145 #[diagnostic(code("Qsc.Eval.ResultComparisonUnsupported"))]
146 #[diagnostic(help("comparing measurement results is not supported when performing circuit synthesis or base profile QIR generation"))]
147 ResultComparisonUnsupported(#[label("cannot compare to result")] PackageSpan),
148
149 #[error("name is not bound")]
150 #[diagnostic(code("Qsc.Eval.UnboundName"))]
151 UnboundName(#[label] PackageSpan),
152
153 #[error("unknown intrinsic `{0}`")]
154 #[diagnostic(code("Qsc.Eval.UnknownIntrinsic"))]
155 UnknownIntrinsic(
156 String,
157 #[label("callable has no implementation")] PackageSpan,
158 ),
159
160 #[error("unsupported return type for intrinsic `{0}`")]
161 #[diagnostic(help("intrinsic callable return type should be `Unit`"))]
162 #[diagnostic(code("Qsc.Eval.UnsupportedIntrinsicType"))]
163 UnsupportedIntrinsicType(String, #[label] PackageSpan),
164
165 #[error("program failed: {0}")]
166 #[diagnostic(code("Qsc.Eval.UserFail"))]
167 UserFail(String, #[label("explicit fail")] PackageSpan),
168}
169
170impl Error {
171 #[must_use]
172 pub fn span(&self) -> &PackageSpan {
173 match self {
174 Error::ArrayTooLarge(span)
175 | Error::CallableAlreadyCounted(span)
176 | Error::CallableNotCounted(span)
177 | Error::DivZero(span)
178 | Error::EmptyRange(span)
179 | Error::IndexOutOfRange(_, span)
180 | Error::InvalidIndex(_, span)
181 | Error::IntrinsicFail(_, _, span)
182 | Error::IntTooLarge(_, span)
183 | Error::InvalidRotationAngle(_, span)
184 | Error::InvalidNegativeInt(_, span)
185 | Error::OutputFail(span)
186 | Error::QubitUniqueness(span)
187 | Error::QubitsAlreadyCounted(span)
188 | Error::QubitsNotCounted(span)
189 | Error::QubitsNotSeparable(span)
190 | Error::RangeStepZero(span)
191 | Error::ReleasedQubitNotZero(_, span)
192 | Error::ResultComparisonUnsupported(span)
193 | Error::UnboundName(span)
194 | Error::UnknownIntrinsic(_, span)
195 | Error::UnsupportedIntrinsicType(_, span)
196 | Error::UserFail(_, span)
197 | Error::InvalidArrayLength(_, span) => span,
198 }
199 }
200}
201
202/// A specialization that may be implemented for an operation.
203enum Spec {
204 /// The default specialization.
205 Body,
206 /// The adjoint specialization.
207 Adj,
208 /// The controlled specialization.
209 Ctl,
210 /// The controlled adjoint specialization.
211 CtlAdj,
212}
213
214impl Display for Spec {
215 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
216 match self {
217 Spec::Body => f.write_str("body"),
218 Spec::Adj => f.write_str("adjoint"),
219 Spec::Ctl => f.write_str("controlled"),
220 Spec::CtlAdj => f.write_str("controlled adjoint"),
221 }
222 }
223}
224
225/// Utility function to identify a subset of a control flow graph corresponding to a given
226/// range.
227#[must_use]
228pub fn exec_graph_section(graph: &ExecGraph, range: ops::Range<usize>) -> ExecGraph {
229 let start: u32 = range
230 .start
231 .try_into()
232 .expect("exec graph ranges should fit into u32");
233 graph[range]
234 .iter()
235 .map(|node| match node {
236 ExecGraphNode::Jump(idx) => ExecGraphNode::Jump(idx - start),
237 ExecGraphNode::JumpIf(idx) => ExecGraphNode::JumpIf(idx - start),
238 ExecGraphNode::JumpIfNot(idx) => ExecGraphNode::JumpIfNot(idx - start),
239 _ => *node,
240 })
241 .collect::<Vec<_>>()
242 .into()
243}
244
245/// Evaluates the given code with the given context.
246/// # Errors
247/// Returns the first error encountered during execution.
248/// # Panics
249/// On internal error where no result is returned.
250pub fn eval(
251 package: PackageId,
252 seed: Option<u64>,
253 exec_graph: ExecGraph,
254 globals: &impl PackageStoreLookup,
255 env: &mut Env,
256 sim: &mut impl Backend<ResultType = impl Into<val::Result>>,
257 receiver: &mut impl Receiver,
258) -> Result<Value, (Error, Vec<Frame>)> {
259 let mut state = State::new(package, exec_graph, seed);
260 let res = state.eval(globals, env, sim, receiver, &[], StepAction::Continue)?;
261 let StepResult::Return(value) = res else {
262 panic!("eval should always return a value");
263 };
264 Ok(value)
265}
266
267/// The type of step action to take during evaluation
268#[derive(Debug, Copy, Clone, Eq, PartialEq)]
269pub enum StepAction {
270 Next,
271 In,
272 Out,
273 Continue,
274}
275
276// The result of an evaluation step.
277#[derive(Clone, Debug)]
278pub enum StepResult {
279 BreakpointHit(StmtId),
280 Next,
281 StepIn,
282 StepOut,
283 Return(Value),
284}
285
286trait AsIndex {
287 type Output;
288
289 fn as_index(&self, index_source: PackageSpan) -> Self::Output;
290}
291
292impl AsIndex for i64 {
293 type Output = Result<usize, Error>;
294
295 fn as_index(&self, index_source: PackageSpan) -> Self::Output {
296 match (*self).try_into() {
297 Ok(index) => Ok(index),
298 Err(_) => Err(Error::InvalidIndex(*self, index_source)),
299 }
300 }
301}
302
303#[derive(Debug, Clone)]
304pub struct Variable {
305 pub name: Rc<str>,
306 pub value: Value,
307 pub span: Span,
308}
309
310#[derive(Debug, Clone)]
311pub struct VariableInfo {
312 pub value: Value,
313 pub name: Rc<str>,
314 pub type_name: String,
315 pub span: Span,
316}
317
318pub struct Range {
319 step: i64,
320 end: i64,
321 curr: i64,
322}
323
324impl Iterator for Range {
325 type Item = i64;
326
327 fn next(&mut self) -> Option<Self::Item> {
328 let curr = self.curr;
329 self.curr += self.step;
330 if (self.step > 0 && curr <= self.end) || (self.step < 0 && curr >= self.end) {
331 Some(curr)
332 } else {
333 None
334 }
335 }
336}
337
338impl Range {
339 fn new(start: i64, step: i64, end: i64) -> Self {
340 Range {
341 step,
342 end,
343 curr: start,
344 }
345 }
346}
347
348pub struct Env(Vec<Scope>);
349
350impl Default for Env {
351 #[must_use]
352 fn default() -> Self {
353 // Always create a global scope for top-level statements.
354 Self(vec![Scope::default()])
355 }
356}
357
358impl Env {
359 #[must_use]
360 pub fn get(&self, id: LocalVarId) -> Option<&Variable> {
361 self.0.iter().rev().find_map(|scope| scope.bindings.get(id))
362 }
363
364 fn get_mut(&mut self, id: LocalVarId) -> Option<&mut Variable> {
365 self.0
366 .iter_mut()
367 .rev()
368 .find_map(|scope| scope.bindings.get_mut(id))
369 }
370
371 pub fn push_scope(&mut self, frame_id: usize) {
372 let scope = Scope {
373 frame_id,
374 ..Default::default()
375 };
376 self.0.push(scope);
377 }
378
379 pub fn leave_scope(&mut self) {
380 // Only pop the scope if there is more than one scope in the stack,
381 // because the global/top-level scope cannot be exited.
382 if self.0.len() > 1 {
383 self.0
384 .pop()
385 .expect("scope should have more than one entry.");
386 }
387 }
388
389 pub fn leave_current_frame(&mut self) {
390 let current_frame_id = self
391 .0
392 .last()
393 .expect("should be at least one scope")
394 .frame_id;
395 if current_frame_id == 0 {
396 // Do not remove the global scope.
397 return;
398 }
399 self.0.retain(|scope| scope.frame_id != current_frame_id);
400 }
401
402 pub fn bind_variable_in_top_frame(&mut self, local_var_id: LocalVarId, var: Variable) {
403 let Some(scope) = self.0.last_mut() else {
404 panic!("no frames in scope");
405 };
406
407 scope.bindings.insert(local_var_id, var);
408 }
409
410 #[must_use]
411 pub fn get_variables_in_top_frame(&self) -> Vec<VariableInfo> {
412 if let Some(scope) = self.0.last() {
413 self.get_variables_in_frame(scope.frame_id)
414 } else {
415 vec![]
416 }
417 }
418
419 #[must_use]
420 pub fn get_variables_in_frame(&self, frame_id: usize) -> Vec<VariableInfo> {
421 let candidate_scopes: Vec<_> = self
422 .0
423 .iter()
424 .filter(|scope| scope.frame_id == frame_id)
425 .map(|scope| scope.bindings.iter())
426 .collect();
427
428 let variables_by_scope: Vec<Vec<VariableInfo>> = candidate_scopes
429 .into_iter()
430 .map(|bindings| {
431 bindings
432 .map(|(_, var)| VariableInfo {
433 name: var.name.clone(),
434 type_name: var.value.type_name().to_string(),
435 value: var.value.clone(),
436 span: var.span,
437 })
438 .collect()
439 })
440 .collect();
441 variables_by_scope.into_iter().flatten().collect::<Vec<_>>()
442 }
443
444 #[allow(clippy::len_without_is_empty)]
445 #[must_use]
446 pub fn len(&self) -> usize {
447 self.0.len()
448 }
449
450 pub fn update_variable_in_top_frame(&mut self, local_var_id: LocalVarId, value: Value) {
451 let variable = self
452 .get_mut(local_var_id)
453 .expect("local variable is not present");
454 variable.value = value;
455 }
456}
457
458#[derive(Default)]
459struct Scope {
460 bindings: IndexMap<LocalVarId, Variable>,
461 frame_id: usize,
462}
463
464type CallableCountKey = (StoreItemId, bool, bool);
465
466pub struct State {
467 exec_graph_stack: Vec<ExecGraph>,
468 idx: u32,
469 idx_stack: Vec<u32>,
470 val_register: Option<Value>,
471 val_stack: Vec<Vec<Value>>,
472 source_package: PackageId,
473 package: PackageId,
474 call_stack: CallStack,
475 current_span: Span,
476 rng: RefCell<StdRng>,
477 call_counts: FxHashMap<CallableCountKey, i64>,
478 qubit_counter: Option<QubitCounter>,
479}
480
481impl State {
482 #[must_use]
483 pub fn new(package: PackageId, exec_graph: ExecGraph, classical_seed: Option<u64>) -> Self {
484 let rng = match classical_seed {
485 Some(seed) => RefCell::new(StdRng::seed_from_u64(seed)),
486 None => RefCell::new(StdRng::from_entropy()),
487 };
488 Self {
489 exec_graph_stack: vec![exec_graph],
490 idx: 0,
491 idx_stack: Vec::new(),
492 val_register: None,
493 val_stack: vec![Vec::new()],
494 source_package: package,
495 package,
496 call_stack: CallStack::default(),
497 current_span: Span::default(),
498 rng,
499 call_counts: FxHashMap::default(),
500 qubit_counter: None,
501 }
502 }
503
504 fn push_frame(&mut self, exec_graph: ExecGraph, id: StoreItemId, functor: FunctorApp) {
505 self.call_stack.push_frame(Frame {
506 span: self.current_span,
507 id,
508 caller: self.package,
509 functor,
510 });
511 self.exec_graph_stack.push(exec_graph);
512 self.val_stack.push(Vec::new());
513 self.idx_stack.push(self.idx);
514 self.idx = 0;
515 self.package = id.package;
516 }
517
518 fn leave_frame(&mut self) {
519 if let Some(frame) = self.call_stack.pop_frame() {
520 self.package = frame.caller;
521 };
522 self.val_stack.pop();
523 self.idx = self.idx_stack.pop().unwrap_or_default();
524 self.exec_graph_stack.pop();
525 }
526
527 fn push_scope(&mut self, env: &mut Env) {
528 env.push_scope(self.call_stack.len());
529 }
530
531 fn take_val_register(&mut self) -> Value {
532 self.val_register.take().expect("value should be present")
533 }
534
535 fn set_val_register(&mut self, val: Value) {
536 self.val_register = Some(val);
537 }
538
539 fn pop_val(&mut self) -> Value {
540 self.val_stack
541 .last_mut()
542 .expect("should have at least one value frame")
543 .pop()
544 .expect("value should be present")
545 }
546
547 fn pop_vals(&mut self, len: usize) -> Vec<Value> {
548 let last = self
549 .val_stack
550 .last_mut()
551 .expect("should have at least one value frame");
552 last.drain(last.len() - len..).collect()
553 }
554
555 fn push_val(&mut self) {
556 let val = self.take_val_register();
557 self.val_stack
558 .last_mut()
559 .expect("should have at least one value frame")
560 .push(val);
561 }
562
563 #[must_use]
564 pub fn get_stack_frames(&self) -> Vec<Frame> {
565 let mut frames = self.call_stack.clone().into_frames();
566
567 let mut span = self.current_span;
568 for frame in frames.iter_mut().rev() {
569 std::mem::swap(&mut frame.span, &mut span);
570 }
571 frames
572 }
573
574 /// # Errors
575 /// Returns the first error encountered during execution.
576 /// # Panics
577 /// When returning a value in the middle of execution.
578 pub fn eval(
579 &mut self,
580 globals: &impl PackageStoreLookup,
581 env: &mut Env,
582 sim: &mut impl Backend<ResultType = impl Into<val::Result>>,
583 out: &mut impl Receiver,
584 breakpoints: &[StmtId],
585 step: StepAction,
586 ) -> Result<StepResult, (Error, Vec<Frame>)> {
587 let current_frame = self.call_stack.len();
588 while !self.exec_graph_stack.is_empty() {
589 let exec_graph = self
590 .exec_graph_stack
591 .last()
592 .expect("should have at least one stack frame");
593 let res = match exec_graph.get(self.idx as usize) {
594 Some(ExecGraphNode::Bind(pat)) => {
595 self.idx += 1;
596 self.eval_bind(env, globals, *pat);
597 continue;
598 }
599 Some(ExecGraphNode::Expr(expr)) => {
600 self.idx += 1;
601 self.eval_expr(env, sim, globals, out, *expr)
602 .map_err(|e| (e, self.get_stack_frames()))?;
603 continue;
604 }
605 Some(ExecGraphNode::Stmt(stmt)) => {
606 self.idx += 1;
607 self.current_span = globals.get_stmt((self.package, *stmt).into()).span;
608
609 match self.check_for_break(breakpoints, *stmt, step, current_frame) {
610 Some(value) => value,
611 None => continue,
612 }
613 }
614 Some(ExecGraphNode::Jump(idx)) => {
615 self.idx = *idx;
616 continue;
617 }
618 Some(ExecGraphNode::JumpIf(idx)) => {
619 let cond = self.val_register == Some(Value::Bool(true));
620 if cond {
621 self.idx = *idx;
622 } else {
623 self.idx += 1;
624 }
625 continue;
626 }
627 Some(ExecGraphNode::JumpIfNot(idx)) => {
628 let cond = self.val_register == Some(Value::Bool(true));
629 if cond {
630 self.idx += 1;
631 } else {
632 self.idx = *idx;
633 }
634 continue;
635 }
636 Some(ExecGraphNode::Store) => {
637 self.push_val();
638 self.idx += 1;
639 continue;
640 }
641 Some(ExecGraphNode::Unit) => {
642 self.idx += 1;
643 self.set_val_register(Value::unit());
644 continue;
645 }
646 Some(ExecGraphNode::Ret) => {
647 self.leave_frame();
648 env.leave_scope();
649 continue;
650 }
651 Some(ExecGraphNode::RetFrame) => {
652 self.leave_frame();
653 env.leave_current_frame();
654 continue;
655 }
656 Some(ExecGraphNode::PushScope) => {
657 self.push_scope(env);
658 self.idx += 1;
659 continue;
660 }
661 Some(ExecGraphNode::PopScope) => {
662 env.leave_scope();
663 self.idx += 1;
664 continue;
665 }
666 None => {
667 // We have reached the end of the current graph without reaching an explicit return node,
668 // usually indicating the partial execution of a single sub-expression.
669 // This means we should pop the execution graph but not the current environment scope,
670 // so bound variables are still accessible after completion.
671 self.exec_graph_stack.pop();
672 assert!(self.exec_graph_stack.is_empty());
673 continue;
674 }
675 };
676
677 if let StepResult::Return(_) = res {
678 panic!("unexpected return");
679 }
680
681 return Ok(res);
682 }
683
684 Ok(StepResult::Return(self.get_result()))
685 }
686
687 fn check_for_break(
688 &self,
689 breakpoints: &[StmtId],
690 stmt: StmtId,
691 step: StepAction,
692 current_frame: usize,
693 ) -> Option<StepResult> {
694 Some(
695 if let Some(bp) = breakpoints
696 .iter()
697 .find(|&bp| *bp == stmt && self.package == self.source_package)
698 {
699 StepResult::BreakpointHit(*bp)
700 } else {
701 if self.current_span == Span::default() {
702 // if there is no span, we are in generated code, so we should skip
703 return None;
704 }
705 // no breakpoint, but we may stop here
706 if step == StepAction::In {
707 StepResult::StepIn
708 } else if step == StepAction::Next && current_frame >= self.call_stack.len() {
709 StepResult::Next
710 } else if step == StepAction::Out && current_frame > self.call_stack.len() {
711 StepResult::StepOut
712 } else {
713 return None;
714 }
715 },
716 )
717 }
718
719 pub fn get_result(&mut self) -> Value {
720 // Some executions don't have any statements to execute,
721 // such as a fragment that has only item definitions.
722 // In that case, the values are empty and the result is unit.
723 self.val_register.take().unwrap_or_else(Value::unit)
724 }
725
726 #[allow(clippy::similar_names)]
727 fn eval_expr(
728 &mut self,
729 env: &mut Env,
730 sim: &mut impl Backend<ResultType = impl Into<val::Result>>,
731 globals: &impl PackageStoreLookup,
732 out: &mut impl Receiver,
733 expr: ExprId,
734 ) -> Result<(), Error> {
735 let expr = globals.get_expr((self.package, expr).into());
736 self.current_span = expr.span;
737 match &expr.kind {
738 ExprKind::Array(arr) => self.eval_arr(arr.len()),
739 ExprKind::ArrayLit(arr) => self.eval_arr_lit(arr, globals),
740 ExprKind::ArrayRepeat(..) => self.eval_arr_repeat(expr.span)?,
741 ExprKind::Assign(lhs, _) => self.eval_assign(env, globals, *lhs)?,
742 ExprKind::AssignOp(op, lhs, rhs) => {
743 let rhs_span = globals.get_expr((self.package, *rhs).into()).span;
744 let (is_array, is_unique) =
745 is_updatable_in_place(env, globals.get_expr((self.package, *lhs).into()));
746 if is_array {
747 if is_unique {
748 self.eval_array_append_in_place(env, globals, *lhs)?;
749 return Ok(());
750 }
751 let rhs_val = self.take_val_register();
752 self.eval_expr(env, sim, globals, out, *lhs)?;
753 self.push_val();
754 self.set_val_register(rhs_val);
755 }
756 self.eval_binop(*op, rhs_span)?;
757 self.eval_assign(env, globals, *lhs)?;
758 }
759 ExprKind::AssignField(record, field, _) => {
760 self.eval_update_field(field.clone());
761 self.eval_assign(env, globals, *record)?;
762 }
763 ExprKind::AssignIndex(lhs, mid, _) => {
764 let mid_span = globals.get_expr((self.package, *mid).into()).span;
765 let (_, is_unique) =
766 is_updatable_in_place(env, globals.get_expr((self.package, *lhs).into()));
767 if is_unique {
768 self.eval_update_index_in_place(env, globals, *lhs, mid_span)?;
769 return Ok(());
770 }
771 self.push_val();
772 self.eval_expr(env, sim, globals, out, *lhs)?;
773 self.eval_update_index(mid_span)?;
774 self.eval_assign(env, globals, *lhs)?;
775 }
776 ExprKind::BinOp(op, _, rhs) => {
777 let rhs_span = globals.get_expr((self.package, *rhs).into()).span;
778 self.eval_binop(*op, rhs_span)?;
779 }
780 ExprKind::Block(..) => panic!("block expr should be handled by control flow"),
781 ExprKind::Call(callee_expr, args_expr) => {
782 let callable_span = globals.get_expr((self.package, *callee_expr).into()).span;
783 let args_span = globals.get_expr((self.package, *args_expr).into()).span;
784 self.eval_call(env, sim, globals, callable_span, args_span, out)?;
785 }
786 ExprKind::Closure(args, callable) => {
787 let closure = resolve_closure(env, self.package, expr.span, args, *callable)?;
788 self.set_val_register(closure);
789 }
790 ExprKind::Fail(..) => {
791 return Err(Error::UserFail(
792 self.take_val_register().unwrap_string().to_string(),
793 self.to_global_span(expr.span),
794 ));
795 }
796 ExprKind::Field(_, field) => self.eval_field(field.clone()),
797 ExprKind::Hole => panic!("hole expr should be disallowed by passes"),
798 ExprKind::If(..) => {
799 panic!("if expr should be handled by control flow")
800 }
801 ExprKind::Index(_, rhs) => {
802 let rhs_span = globals.get_expr((self.package, *rhs).into()).span;
803 self.eval_index(rhs_span)?;
804 }
805 ExprKind::Lit(lit) => {
806 self.set_val_register(lit_to_val(lit));
807 }
808 ExprKind::Range(start, step, end) => {
809 self.eval_range(start.is_some(), step.is_some(), end.is_some());
810 }
811 ExprKind::Return(..) => panic!("return expr should be handled by control flow"),
812 ExprKind::Struct(_, copy, fields) => self.eval_struct(*copy, fields),
813 ExprKind::String(components) => self.collect_string(components),
814 ExprKind::UpdateIndex(_, mid, _) => {
815 let mid_span = globals.get_expr((self.package, *mid).into()).span;
816 self.eval_update_index(mid_span)?;
817 }
818 ExprKind::Tuple(tup) => self.eval_tup(tup.len()),
819 ExprKind::UnOp(op, _) => self.eval_unop(*op),
820 ExprKind::UpdateField(_, field, _) => {
821 self.eval_update_field(field.clone());
822 }
823 ExprKind::Var(res, _) => {
824 self.set_val_register(resolve_binding(env, self.package, *res, expr.span)?);
825 }
826 ExprKind::While(..) => {
827 panic!("while expr should be handled by control flow")
828 }
829 }
830
831 Ok(())
832 }
833
834 fn collect_string(&mut self, components: &[StringComponent]) {
835 if let [StringComponent::Lit(str)] = components {
836 self.set_val_register(Value::String(Rc::clone(str)));
837 return;
838 }
839
840 let mut string = String::new();
841 for component in components.iter().rev() {
842 match component {
843 StringComponent::Expr(..) => {
844 let expr_str = format!("{}", self.pop_val());
845 string.insert_str(0, &expr_str);
846 }
847 StringComponent::Lit(lit) => {
848 string.insert_str(0, lit);
849 }
850 }
851 }
852 self.set_val_register(Value::String(Rc::from(string)));
853 }
854
855 fn eval_arr(&mut self, len: usize) {
856 let arr = self.pop_vals(len);
857 self.set_val_register(Value::Array(arr.into()));
858 }
859
860 fn eval_arr_lit(&mut self, arr: &Vec<ExprId>, globals: &impl PackageStoreLookup) {
861 let mut new_arr: Rc<Vec<Value>> = Rc::new(Vec::with_capacity(arr.len()));
862 for id in arr {
863 let ExprKind::Lit(lit) = &globals.get_expr((self.package, *id).into()).kind else {
864 panic!("expr kind should be lit")
865 };
866 Rc::get_mut(&mut new_arr)
867 .expect("array should be uniquely referenced")
868 .push(lit_to_val(lit));
869 }
870 self.set_val_register(Value::Array(new_arr));
871 }
872
873 fn eval_array_append_in_place(
874 &mut self,
875 env: &mut Env,
876 globals: &impl PackageStoreLookup,
877 lhs: ExprId,
878 ) -> Result<(), Error> {
879 let lhs = globals.get_expr((self.package, lhs).into());
880 let rhs = self.take_val_register();
881 match (&lhs.kind, rhs) {
882 (&ExprKind::Var(Res::Local(id), _), rhs) => match env.get_mut(id) {
883 Some(var) => {
884 var.value.append_array(rhs);
885 }
886 None => return Err(Error::UnboundName(self.to_global_span(lhs.span))),
887 },
888 _ => unreachable!("unassignable array update pattern should be disallowed by compiler"),
889 }
890 Ok(())
891 }
892
893 fn eval_arr_repeat(&mut self, span: Span) -> Result<(), Error> {
894 let size_val = self.take_val_register().unwrap_int();
895 let item_val = self.pop_val();
896 let s = match size_val.try_into() {
897 Ok(i) => Ok(i),
898 Err(_) => Err(Error::InvalidArrayLength(
899 size_val,
900 self.to_global_span(span),
901 )),
902 }?;
903 self.set_val_register(Value::Array(vec![item_val; s].into()));
904 Ok(())
905 }
906
907 fn eval_assign(
908 &mut self,
909 env: &mut Env,
910 globals: &impl PackageStoreLookup,
911 lhs: ExprId,
912 ) -> Result<(), Error> {
913 let rhs = self.take_val_register();
914 self.update_binding(env, globals, lhs, rhs)
915 }
916
917 fn eval_bind(&mut self, env: &mut Env, globals: &impl PackageStoreLookup, pat: PatId) {
918 let val = self.take_val_register();
919 self.bind_value(env, globals, pat, val);
920 }
921
922 fn eval_binop(&mut self, op: BinOp, span: Span) -> Result<(), Error> {
923 match op {
924 BinOp::Add => self.eval_binop_simple(eval_binop_add),
925 BinOp::AndB => self.eval_binop_simple(eval_binop_andb),
926 BinOp::Div => self.eval_binop_with_error(span, eval_binop_div)?,
927 BinOp::Eq => self.eval_binop_with_error(span, eval_binop_eq)?,
928 BinOp::Exp => self.eval_binop_with_error(span, eval_binop_exp)?,
929 BinOp::Gt => self.eval_binop_simple(eval_binop_gt),
930 BinOp::Gte => self.eval_binop_simple(eval_binop_gte),
931 BinOp::Lt => self.eval_binop_simple(eval_binop_lt),
932 BinOp::Lte => self.eval_binop_simple(eval_binop_lte),
933 BinOp::Mod => self.eval_binop_with_error(span, eval_binop_mod)?,
934 BinOp::Mul => self.eval_binop_simple(eval_binop_mul),
935 BinOp::Neq => self.eval_binop_with_error(span, eval_binop_neq)?,
936 BinOp::OrB => self.eval_binop_simple(eval_binop_orb),
937 BinOp::Shl => self.eval_binop_with_error(span, eval_binop_shl)?,
938 BinOp::Shr => self.eval_binop_with_error(span, eval_binop_shr)?,
939 BinOp::Sub => self.eval_binop_simple(eval_binop_sub),
940 BinOp::XorB => self.eval_binop_simple(eval_binop_xorb),
941
942 // Logical operators should be handled by control flow
943 BinOp::AndL | BinOp::OrL => {}
944 }
945 Ok(())
946 }
947
948 fn eval_binop_simple(&mut self, binop_func: impl FnOnce(Value, Value) -> Value) {
949 let rhs_val = self.take_val_register();
950 let lhs_val = self.pop_val();
951 self.set_val_register(binop_func(lhs_val, rhs_val));
952 }
953
954 fn eval_binop_with_error(
955 &mut self,
956 span: Span,
957 binop_func: impl FnOnce(Value, Value, PackageSpan) -> Result<Value, Error>,
958 ) -> Result<(), Error> {
959 let span = self.to_global_span(span);
960 let rhs_val = self.take_val_register();
961 let lhs_val = self.pop_val();
962 self.set_val_register(binop_func(lhs_val, rhs_val, span)?);
963 Ok(())
964 }
965
966 fn eval_call(
967 &mut self,
968 env: &mut Env,
969 sim: &mut impl Backend<ResultType = impl Into<val::Result>>,
970 globals: &impl PackageStoreLookup,
971 callable_span: Span,
972 arg_span: Span,
973 out: &mut impl Receiver,
974 ) -> Result<(), Error> {
975 let arg = self.take_val_register();
976 let (callee_id, functor, fixed_args) = match self.pop_val() {
977 Value::Closure(inner) => (inner.id, inner.functor, Some(inner.fixed_args)),
978 Value::Global(id, functor) => (id, functor, None),
979 _ => panic!("value is not callable"),
980 };
981
982 let arg_span = self.to_global_span(arg_span);
983
984 let callee = match globals.get_global(callee_id) {
985 Some(Global::Callable(callable)) => callable,
986 Some(Global::Udt) => {
987 self.set_val_register(arg);
988 return Ok(());
989 }
990 None => return Err(Error::UnboundName(self.to_global_span(callable_span))),
991 };
992
993 let callee_span = self.to_global_span(callee.span);
994
995 let spec = spec_from_functor_app(functor);
996 match &callee.implementation {
997 CallableImpl::Intrinsic if is_counting_call(&callee.name.name) => {
998 self.push_frame(Vec::new().into(), callee_id, functor);
999
1000 let val = self.counting_call(&callee.name.name, arg, arg_span)?;
1001
1002 self.set_val_register(val);
1003 self.leave_frame();
1004 Ok(())
1005 }
1006 CallableImpl::Intrinsic => {
1007 self.push_frame(Vec::new().into(), callee_id, functor);
1008
1009 self.increment_call_count(callee_id, functor);
1010
1011 let name = &callee.name.name;
1012 let val = intrinsic::call(
1013 name,
1014 callee_span,
1015 arg,
1016 arg_span,
1017 sim,
1018 &mut self.rng.borrow_mut(),
1019 out,
1020 )?;
1021 if val == Value::unit() && callee.output != Ty::UNIT {
1022 return Err(Error::UnsupportedIntrinsicType(
1023 callee.name.name.to_string(),
1024 callee_span,
1025 ));
1026 }
1027
1028 // If qubit counting is enabled, update the qubit counter when the intrinsic for allocation is called.
1029 if let (Some(counter), "__quantum__rt__qubit_allocate", Value::Qubit(q)) =
1030 (&mut self.qubit_counter, name.as_ref(), &val)
1031 {
1032 counter.allocated(q.0);
1033 }
1034
1035 self.set_val_register(val);
1036 self.leave_frame();
1037 Ok(())
1038 }
1039 CallableImpl::Spec(specialized_implementation) => {
1040 let spec_decl = match spec {
1041 Spec::Body => Some(&specialized_implementation.body),
1042 Spec::Adj => specialized_implementation.adj.as_ref(),
1043 Spec::Ctl => specialized_implementation.ctl.as_ref(),
1044 Spec::CtlAdj => specialized_implementation.ctl_adj.as_ref(),
1045 }
1046 .expect("missing specialization should be a compilation error");
1047 self.push_frame(spec_decl.exec_graph.clone(), callee_id, functor);
1048 self.push_scope(env);
1049 self.increment_call_count(callee_id, functor);
1050
1051 self.bind_args_for_spec(
1052 env,
1053 globals,
1054 callee.input,
1055 spec_decl.input,
1056 arg,
1057 arg_span,
1058 functor.controlled,
1059 fixed_args,
1060 )?;
1061 Ok(())
1062 }
1063 CallableImpl::SimulatableIntrinsic(spec_decl) => {
1064 self.push_frame(spec_decl.exec_graph.clone(), callee_id, functor);
1065 self.push_scope(env);
1066
1067 self.bind_args_for_spec(
1068 env,
1069 globals,
1070 callee.input,
1071 spec_decl.input,
1072 arg,
1073 arg_span,
1074 functor.controlled,
1075 fixed_args,
1076 )?;
1077 Ok(())
1078 }
1079 }
1080 }
1081
1082 fn eval_field(&mut self, field: Field) {
1083 let record = self.take_val_register();
1084 let val = match (record, field) {
1085 (Value::Range(inner), Field::Prim(PrimField::Start)) => Value::Int(
1086 inner
1087 .start
1088 .expect("range access should be validated by compiler"),
1089 ),
1090 (Value::Range(inner), Field::Prim(PrimField::Step)) => Value::Int(inner.step),
1091 (Value::Range(inner), Field::Prim(PrimField::End)) => Value::Int(
1092 inner
1093 .end
1094 .expect("range access should be validated by compiler"),
1095 ),
1096 (record, Field::Path(path)) => {
1097 follow_field_path(record, &path.indices).expect("field path should be valid")
1098 }
1099 _ => panic!("invalid field access"),
1100 };
1101 self.set_val_register(val);
1102 }
1103
1104 fn eval_index(&mut self, span: Span) -> Result<(), Error> {
1105 let index_val = self.take_val_register();
1106 let arr = self.pop_val().unwrap_array();
1107 match &index_val {
1108 Value::Int(i) => {
1109 self.set_val_register(index_array(&arr, *i, self.to_global_span(span))?);
1110 }
1111 Value::Range(inner) => {
1112 self.set_val_register(slice_array(
1113 &arr,
1114 inner.start,
1115 inner.step,
1116 inner.end,
1117 self.to_global_span(span),
1118 )?);
1119 }
1120 _ => panic!("array should only be indexed by Int or Range"),
1121 }
1122 Ok(())
1123 }
1124
1125 fn eval_range(&mut self, has_start: bool, has_step: bool, has_end: bool) {
1126 let end = if has_end {
1127 Some(self.take_val_register().unwrap_int())
1128 } else {
1129 None
1130 };
1131 let step = if has_step {
1132 self.pop_val().unwrap_int()
1133 } else {
1134 val::DEFAULT_RANGE_STEP
1135 };
1136 let start = if has_start {
1137 Some(self.pop_val().unwrap_int())
1138 } else {
1139 None
1140 };
1141 self.set_val_register(Value::Range(val::Range { start, step, end }.into()));
1142 }
1143
1144 fn eval_struct(&mut self, copy: Option<ExprId>, fields: &[FieldAssign]) {
1145 // Extract a flat list of field indexes.
1146 let field_indexes = fields
1147 .iter()
1148 .map(|f| match &f.field {
1149 Field::Path(path) => match path.indices.as_slice() {
1150 &[i] => i,
1151 _ => panic!("field path for struct should have a single index"),
1152 },
1153 _ => panic!("invalid field for struct"),
1154 })
1155 .collect::<Vec<_>>();
1156
1157 let len = fields.len();
1158
1159 let (field_vals, mut strct) = if copy.is_some() {
1160 // Get the field values and the copy struct value.
1161 let field_vals = self.pop_vals(len + 1);
1162 let (copy, field_vals) = field_vals.split_first().expect("copy value is expected");
1163
1164 // Make a clone of the copy struct value.
1165 (field_vals.to_vec(), copy.clone().unwrap_tuple().to_vec())
1166 } else {
1167 // Make an empty struct of the appropriate size.
1168 (self.pop_vals(len), vec![Value::Int(0); len])
1169 };
1170
1171 // Insert the field values into the new struct.
1172 assert!(
1173 field_vals.len() == field_indexes.len(),
1174 "number of given field values should match the number of given struct fields"
1175 );
1176 for (i, val) in field_indexes.iter().zip(field_vals.into_iter()) {
1177 strct[*i] = val;
1178 }
1179
1180 self.set_val_register(Value::Tuple(strct.into()));
1181 }
1182
1183 fn eval_update_index(&mut self, span: Span) -> Result<(), Error> {
1184 let values = self.take_val_register().unwrap_array();
1185 let update = self.pop_val();
1186 let index = self.pop_val();
1187 let span = self.to_global_span(span);
1188 match index {
1189 Value::Int(index) => self.eval_update_index_single(&values, index, update, span),
1190 Value::Range(inner) => self.eval_update_index_range(
1191 &values,
1192 inner.start,
1193 inner.step,
1194 inner.end,
1195 update,
1196 span,
1197 ),
1198 _ => unreachable!("array should only be indexed by Int or Range"),
1199 }
1200 }
1201
1202 fn eval_update_index_single(
1203 &mut self,
1204 values: &[Value],
1205 index: i64,
1206 update: Value,
1207 span: PackageSpan,
1208 ) -> Result<(), Error> {
1209 let updated_array = update_index_single(values, index, update, span)?;
1210 self.set_val_register(updated_array);
1211 Ok(())
1212 }
1213
1214 fn eval_update_index_range(
1215 &mut self,
1216 values: &[Value],
1217 start: Option<i64>,
1218 step: i64,
1219 end: Option<i64>,
1220 update: Value,
1221 span: PackageSpan,
1222 ) -> Result<(), Error> {
1223 let updated_array = update_index_range(values, start, step, end, update, span)?;
1224 self.set_val_register(updated_array);
1225 Ok(())
1226 }
1227
1228 fn eval_update_index_in_place(
1229 &mut self,
1230 env: &mut Env,
1231 globals: &impl PackageStoreLookup,
1232 lhs: ExprId,
1233 span: Span,
1234 ) -> Result<(), Error> {
1235 let update = self.take_val_register();
1236 let index = self.pop_val();
1237 let span = self.to_global_span(span);
1238 match index {
1239 Value::Int(index) => {
1240 if index < 0 {
1241 return Err(Error::InvalidNegativeInt(index, span));
1242 }
1243 let i = index.as_index(span)?;
1244 self.update_array_index_single(env, globals, lhs, span, i, update)
1245 }
1246 range @ Value::Range(..) => {
1247 self.update_array_index_range(env, globals, lhs, span, &range, update)
1248 }
1249 _ => unreachable!("array should only be indexed by Int or Range"),
1250 }
1251 }
1252
1253 fn eval_tup(&mut self, len: usize) {
1254 let tup = self.pop_vals(len);
1255 self.set_val_register(Value::Tuple(tup.into()));
1256 }
1257
1258 fn eval_unop(&mut self, op: UnOp) {
1259 let val = self.take_val_register();
1260 match op {
1261 UnOp::Functor(functor) => match val {
1262 Value::Closure(inner) => {
1263 self.set_val_register(Value::Closure(
1264 val::Closure {
1265 functor: update_functor_app(functor, inner.functor),
1266 ..*inner
1267 }
1268 .into(),
1269 ));
1270 }
1271 Value::Global(id, app) => {
1272 self.set_val_register(Value::Global(id, update_functor_app(functor, app)));
1273 }
1274 _ => panic!("value should be callable"),
1275 },
1276 UnOp::Neg => match val {
1277 Value::BigInt(v) => self.set_val_register(Value::BigInt(v.neg())),
1278 Value::Double(v) => self.set_val_register(Value::Double(v.neg())),
1279 Value::Int(v) => self.set_val_register(Value::Int(v.wrapping_neg())),
1280 _ => panic!("value should be number"),
1281 },
1282 UnOp::NotB => match val {
1283 Value::Int(v) => self.set_val_register(Value::Int(!v)),
1284 Value::BigInt(v) => self.set_val_register(Value::BigInt(!v)),
1285 _ => panic!("value should be Int or BigInt"),
1286 },
1287 UnOp::NotL => match val {
1288 Value::Bool(b) => self.set_val_register(Value::Bool(!b)),
1289 _ => panic!("value should be bool"),
1290 },
1291 UnOp::Pos => match val {
1292 Value::BigInt(_) | Value::Int(_) | Value::Double(_) => self.set_val_register(val),
1293 _ => panic!("value should be number"),
1294 },
1295 UnOp::Unwrap => self.set_val_register(val),
1296 }
1297 }
1298
1299 fn eval_update_field(&mut self, field: Field) {
1300 let record = self.take_val_register();
1301 let value = self.pop_val();
1302 let update = match (record, field) {
1303 (Value::Range(mut inner), Field::Prim(PrimField::Start)) => {
1304 inner.start = Some(value.unwrap_int());
1305 Value::Range(inner)
1306 }
1307 (Value::Range(mut inner), Field::Prim(PrimField::Step)) => {
1308 inner.step = value.unwrap_int();
1309 Value::Range(inner)
1310 }
1311 (Value::Range(mut inner), Field::Prim(PrimField::End)) => {
1312 inner.end = Some(value.unwrap_int());
1313 Value::Range(inner)
1314 }
1315 (record, Field::Path(path)) => update_field_path(&record, &path.indices, &value)
1316 .expect("field path should be valid"),
1317 _ => panic!("invalid field access"),
1318 };
1319 self.set_val_register(update);
1320 }
1321
1322 fn bind_value(&self, env: &mut Env, globals: &impl PackageStoreLookup, pat: PatId, val: Value) {
1323 let pat = globals.get_pat((self.package, pat).into());
1324 match &pat.kind {
1325 PatKind::Bind(variable) => {
1326 let scope = env.0.last_mut().expect("binding should have a scope");
1327 scope.bindings.insert(
1328 variable.id,
1329 Variable {
1330 name: variable.name.clone(),
1331 value: val,
1332 span: variable.span,
1333 },
1334 );
1335 }
1336 PatKind::Discard => {}
1337 PatKind::Tuple(tup) => {
1338 let val_tup = val.unwrap_tuple();
1339 for (pat, val) in tup.iter().zip(val_tup.iter()) {
1340 self.bind_value(env, globals, *pat, val.clone());
1341 }
1342 }
1343 }
1344 }
1345
1346 #[allow(clippy::similar_names)]
1347 fn update_binding(
1348 &self,
1349 env: &mut Env,
1350 globals: &impl PackageStoreLookup,
1351 lhs: ExprId,
1352 rhs: Value,
1353 ) -> Result<(), Error> {
1354 let lhs = globals.get_expr((self.package, lhs).into());
1355 match (&lhs.kind, rhs) {
1356 (ExprKind::Hole, _) => {}
1357 (&ExprKind::Var(Res::Local(id), _), rhs) => match env.get_mut(id) {
1358 Some(var) => {
1359 var.value = rhs;
1360 }
1361 None => return Err(Error::UnboundName(self.to_global_span(lhs.span))),
1362 },
1363 (ExprKind::Tuple(var_tup), Value::Tuple(tup)) => {
1364 for (expr, val) in var_tup.iter().zip(tup.iter()) {
1365 self.update_binding(env, globals, *expr, val.clone())?;
1366 }
1367 }
1368 _ => unreachable!("unassignable pattern should be disallowed by compiler"),
1369 }
1370 Ok(())
1371 }
1372
1373 fn update_array_index_single(
1374 &mut self,
1375 env: &mut Env,
1376 globals: &impl PackageStoreLookup,
1377 lhs: ExprId,
1378 span: PackageSpan,
1379 index: usize,
1380 rhs: Value,
1381 ) -> Result<(), Error> {
1382 let lhs = globals.get_expr((self.package, lhs).into());
1383 match &lhs.kind {
1384 &ExprKind::Var(Res::Local(id), _) => match env.get_mut(id) {
1385 Some(var) => {
1386 var.value.update_array(index, rhs).map_err(|idx| {
1387 Error::IndexOutOfRange(idx.try_into().expect("index should be valid"), span)
1388 })?;
1389 }
1390 None => return Err(Error::UnboundName(self.to_global_span(lhs.span))),
1391 },
1392 _ => unreachable!("unassignable array update pattern should be disallowed by compiler"),
1393 }
1394 Ok(())
1395 }
1396
1397 #[allow(clippy::similar_names)] // `env` and `end` are similar but distinct
1398 fn update_array_index_range(
1399 &mut self,
1400 env: &mut Env,
1401 globals: &impl PackageStoreLookup,
1402 lhs: ExprId,
1403 range_span: PackageSpan,
1404 range: &Value,
1405 update: Value,
1406 ) -> Result<(), Error> {
1407 let lhs = globals.get_expr((self.package, lhs).into());
1408 match &lhs.kind {
1409 &ExprKind::Var(Res::Local(id), _) => match env.get_mut(id) {
1410 Some(var) => {
1411 let rhs = update.unwrap_array();
1412 let Value::Array(arr) = &mut var.value else {
1413 panic!("variable should be an array");
1414 };
1415 let Value::Range(inner) = range else {
1416 unreachable!("range should be a Value::Range");
1417 };
1418 let range = make_range(arr, inner.start, inner.step, inner.end, range_span)?;
1419 for (idx, rhs) in range.into_iter().zip(rhs.iter()) {
1420 if idx < 0 {
1421 return Err(Error::InvalidNegativeInt(idx, range_span));
1422 }
1423 let i = idx.as_index(range_span)?;
1424 var.value.update_array(i, rhs.clone()).map_err(|idx| {
1425 Error::IndexOutOfRange(
1426 idx.try_into().expect("index should be valid"),
1427 range_span,
1428 )
1429 })?;
1430 }
1431 }
1432 None => return Err(Error::UnboundName(self.to_global_span(lhs.span))),
1433 },
1434 _ => unreachable!("unassignable array update pattern should be disallowed by compiler"),
1435 }
1436 Ok(())
1437 }
1438
1439 #[allow(clippy::too_many_arguments)]
1440 fn bind_args_for_spec(
1441 &self,
1442 env: &mut Env,
1443 globals: &impl PackageStoreLookup,
1444 decl_pat: PatId,
1445 spec_pat: Option<PatId>,
1446 args_val: Value,
1447 args_span: PackageSpan,
1448 ctl_count: u8,
1449 fixed_args: Option<Rc<[Value]>>,
1450 ) -> Result<(), Error> {
1451 match spec_pat {
1452 Some(spec_pat) => {
1453 assert!(
1454 ctl_count > 0,
1455 "spec pattern tuple used without controlled functor"
1456 );
1457
1458 let mut tup = args_val;
1459 let mut ctls = vec![];
1460 for _ in 0..ctl_count {
1461 let [c, rest] = &*tup.unwrap_tuple() else {
1462 panic!("tuple should be arity 2");
1463 };
1464 ctls.extend_from_slice(&c.clone().unwrap_array());
1465 tup = rest.clone();
1466 }
1467
1468 if !are_ctls_unique(&ctls, &tup) {
1469 return Err(Error::QubitUniqueness(args_span));
1470 }
1471
1472 self.bind_value(env, globals, spec_pat, Value::Array(ctls.into()));
1473 self.bind_value(env, globals, decl_pat, merge_fixed_args(fixed_args, tup));
1474 }
1475 None => self.bind_value(
1476 env,
1477 globals,
1478 decl_pat,
1479 merge_fixed_args(fixed_args, args_val),
1480 ),
1481 }
1482 Ok(())
1483 }
1484
1485 fn to_global_span(&self, span: Span) -> PackageSpan {
1486 PackageSpan {
1487 package: map_fir_package_to_hir(self.package),
1488 span,
1489 }
1490 }
1491
1492 fn counting_call(&mut self, name: &str, arg: Value, span: PackageSpan) -> Result<Value, Error> {
1493 let counting_key = |arg: Value| match arg {
1494 Value::Closure(closure) => make_counting_key(closure.id, closure.functor),
1495 Value::Global(id, functor) => make_counting_key(id, functor),
1496 _ => panic!("value should be callable"),
1497 };
1498 match name {
1499 "StartCountingOperation" | "StartCountingFunction" => {
1500 if self.call_counts.insert(counting_key(arg), 0).is_some() {
1501 Err(Error::CallableAlreadyCounted(span))
1502 } else {
1503 Ok(Value::unit())
1504 }
1505 }
1506 "StopCountingOperation" | "StopCountingFunction" => {
1507 if let Some(count) = self.call_counts.remove(&counting_key(arg)) {
1508 Ok(Value::Int(count))
1509 } else {
1510 Err(Error::CallableNotCounted(span))
1511 }
1512 }
1513 "StartCountingQubits" => {
1514 if self
1515 .qubit_counter
1516 .replace(QubitCounter::default())
1517 .is_some()
1518 {
1519 Err(Error::QubitsAlreadyCounted(span))
1520 } else {
1521 Ok(Value::unit())
1522 }
1523 }
1524 "StopCountingQubits" => {
1525 if let Some(qubit_counter) = self.qubit_counter.take() {
1526 Ok(Value::Int(qubit_counter.into_count()))
1527 } else {
1528 Err(Error::QubitsNotCounted(span))
1529 }
1530 }
1531 _ => panic!("unknown counting call"),
1532 }
1533 }
1534
1535 fn increment_call_count(&mut self, callee_id: StoreItemId, functor: FunctorApp) {
1536 if let Some(count) = self
1537 .call_counts
1538 .get_mut(&make_counting_key(callee_id, functor))
1539 {
1540 *count += 1;
1541 }
1542 }
1543}
1544
1545pub fn are_ctls_unique(ctls: &[Value], tup: &Value) -> bool {
1546 let mut qubits = FxHashSet::default();
1547 for ctl in ctls.iter().flat_map(Value::qubits) {
1548 if !qubits.insert(ctl) {
1549 return false;
1550 }
1551 }
1552 for qubit in tup.qubits() {
1553 if qubits.contains(&qubit) {
1554 return false;
1555 }
1556 }
1557 true
1558}
1559
1560fn merge_fixed_args(fixed_args: Option<Rc<[Value]>>, arg: Value) -> Value {
1561 if let Some(fixed_args) = fixed_args {
1562 Value::Tuple(fixed_args.iter().cloned().chain(iter::once(arg)).collect())
1563 } else {
1564 arg
1565 }
1566}
1567
1568fn resolve_binding(env: &Env, package: PackageId, res: Res, span: Span) -> Result<Value, Error> {
1569 Ok(match res {
1570 Res::Err => panic!("resolution error"),
1571 Res::Item(item) => Value::Global(
1572 StoreItemId {
1573 package: item.package.unwrap_or(package),
1574 item: item.item,
1575 },
1576 FunctorApp::default(),
1577 ),
1578 Res::Local(id) => env
1579 .get(id)
1580 .ok_or(Error::UnboundName(PackageSpan {
1581 package: map_fir_package_to_hir(package),
1582 span,
1583 }))?
1584 .value
1585 .clone(),
1586 })
1587}
1588
1589fn spec_from_functor_app(functor: FunctorApp) -> Spec {
1590 match (functor.adjoint, functor.controlled) {
1591 (false, 0) => Spec::Body,
1592 (true, 0) => Spec::Adj,
1593 (false, _) => Spec::Ctl,
1594 (true, _) => Spec::CtlAdj,
1595 }
1596}
1597
1598pub fn resolve_closure(
1599 env: &Env,
1600 package: PackageId,
1601 span: Span,
1602 args: &[LocalVarId],
1603 callable: LocalItemId,
1604) -> Result<Value, Error> {
1605 let args: Option<_> = args
1606 .iter()
1607 .map(|&arg| Some(env.get(arg)?.value.clone()))
1608 .collect();
1609 let args: Vec<_> = args.ok_or(Error::UnboundName(PackageSpan {
1610 package: map_fir_package_to_hir(package),
1611 span,
1612 }))?;
1613 let callable = StoreItemId {
1614 package,
1615 item: callable,
1616 };
1617 Ok(Value::Closure(
1618 val::Closure {
1619 fixed_args: args.into(),
1620 id: callable,
1621 functor: FunctorApp::default(),
1622 }
1623 .into(),
1624 ))
1625}
1626
1627fn lit_to_val(lit: &Lit) -> Value {
1628 match lit {
1629 Lit::BigInt(v) => Value::BigInt(v.clone()),
1630 Lit::Bool(v) => Value::Bool(*v),
1631 Lit::Double(v) => Value::Double(*v),
1632 Lit::Int(v) => Value::Int(*v),
1633 Lit::Pauli(v) => Value::Pauli(*v),
1634 Lit::Result(fir::Result::Zero) => Value::RESULT_ZERO,
1635 Lit::Result(fir::Result::One) => Value::RESULT_ONE,
1636 }
1637}
1638
1639fn eval_binop_eq(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1640 match (lhs_val, rhs_val) {
1641 (Value::Result(val::Result::Id(_)), _) | (_, Value::Result(val::Result::Id(_))) => {
1642 // Comparison of result ids is nonsensical, so we prevent it.
1643 // This code path is reachable when using the circuit builder backend
1644 // since we don't currently do runtime capability analysis
1645 // to prevent executing programs that do result comparisons.
1646 Err(Error::ResultComparisonUnsupported(rhs_span))
1647 }
1648 (lhs, rhs) => Ok(Value::Bool(lhs == rhs)),
1649 }
1650}
1651
1652fn eval_binop_neq(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1653 match (lhs_val, rhs_val) {
1654 (Value::Result(val::Result::Id(_)), _) | (_, Value::Result(val::Result::Id(_))) => {
1655 // Comparison of result ids is nonsensical, so we prevent it.
1656 // This code path is reachable when using the circuit builder backend
1657 // since we don't currently do runtime capability analysis
1658 // to prevent executing programs that do result comparisons.
1659 Err(Error::ResultComparisonUnsupported(rhs_span))
1660 }
1661 (lhs, rhs) => Ok(Value::Bool(lhs != rhs)),
1662 }
1663}
1664
1665fn eval_binop_add(lhs_val: Value, rhs_val: Value) -> Value {
1666 match lhs_val {
1667 Value::Array(arr) => {
1668 let rhs_arr = rhs_val.unwrap_array();
1669 let items: Vec<_> = arr.iter().cloned().chain(rhs_arr.iter().cloned()).collect();
1670 Value::Array(items.into())
1671 }
1672 Value::BigInt(val) => {
1673 let rhs = rhs_val.unwrap_big_int();
1674 Value::BigInt(val + rhs)
1675 }
1676 Value::Double(val) => {
1677 let rhs = rhs_val.unwrap_double();
1678 Value::Double(val + rhs)
1679 }
1680 Value::Int(val) => {
1681 let rhs = rhs_val.unwrap_int();
1682 Value::Int(val.wrapping_add(rhs))
1683 }
1684 Value::String(val) => {
1685 let rhs = rhs_val.unwrap_string();
1686 Value::String((val.to_string() + &rhs).into())
1687 }
1688 _ => panic!("value is not addable: {}", lhs_val.type_name()),
1689 }
1690}
1691
1692fn eval_binop_andb(lhs_val: Value, rhs_val: Value) -> Value {
1693 match lhs_val {
1694 Value::BigInt(val) => {
1695 let rhs = rhs_val.unwrap_big_int();
1696 Value::BigInt(val & rhs)
1697 }
1698 Value::Int(val) => {
1699 let rhs = rhs_val.unwrap_int();
1700 Value::Int(val & rhs)
1701 }
1702 _ => panic!("value type does not support andb"),
1703 }
1704}
1705
1706fn eval_binop_div(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1707 match lhs_val {
1708 Value::BigInt(val) => {
1709 let rhs = rhs_val.unwrap_big_int();
1710 if rhs == BigInt::from(0) {
1711 Err(Error::DivZero(rhs_span))
1712 } else {
1713 Ok(Value::BigInt(val / rhs))
1714 }
1715 }
1716 Value::Int(val) => {
1717 let rhs = rhs_val.unwrap_int();
1718 if rhs == 0 {
1719 Err(Error::DivZero(rhs_span))
1720 } else {
1721 Ok(Value::Int(val.wrapping_div(rhs)))
1722 }
1723 }
1724 Value::Double(val) => {
1725 let rhs = rhs_val.unwrap_double();
1726 Ok(Value::Double(val / rhs))
1727 }
1728 _ => panic!("value should support div"),
1729 }
1730}
1731
1732fn eval_binop_exp(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1733 match lhs_val {
1734 Value::BigInt(val) => {
1735 let rhs_val = rhs_val.unwrap_int();
1736 if rhs_val < 0 {
1737 Err(Error::InvalidNegativeInt(rhs_val, rhs_span))
1738 } else {
1739 let rhs_val: u32 = match rhs_val.try_into() {
1740 Ok(v) => Ok(v),
1741 Err(_) => Err(Error::IntTooLarge(rhs_val, rhs_span)),
1742 }?;
1743 Ok(Value::BigInt(val.pow(rhs_val)))
1744 }
1745 }
1746 Value::Double(val) => Ok(Value::Double(val.powf(rhs_val.unwrap_double()))),
1747 Value::Int(val) => {
1748 let rhs_val = rhs_val.unwrap_int();
1749 if rhs_val < 0 {
1750 Err(Error::InvalidNegativeInt(rhs_val, rhs_span))
1751 } else {
1752 let result: i64 = match rhs_val.try_into() {
1753 Ok(v) => val
1754 .checked_pow(v)
1755 .ok_or(Error::IntTooLarge(rhs_val, rhs_span)),
1756 Err(_) => Err(Error::IntTooLarge(rhs_val, rhs_span)),
1757 }?;
1758 Ok(Value::Int(result))
1759 }
1760 }
1761 _ => panic!("value should support exp"),
1762 }
1763}
1764
1765fn eval_binop_gt(lhs_val: Value, rhs_val: Value) -> Value {
1766 match lhs_val {
1767 Value::BigInt(val) => {
1768 let rhs = rhs_val.unwrap_big_int();
1769 Value::Bool(val > rhs)
1770 }
1771 Value::Int(val) => {
1772 let rhs = rhs_val.unwrap_int();
1773 Value::Bool(val > rhs)
1774 }
1775 Value::Double(val) => {
1776 let rhs = rhs_val.unwrap_double();
1777 Value::Bool(val > rhs)
1778 }
1779 _ => panic!("value doesn't support binop gt"),
1780 }
1781}
1782
1783fn eval_binop_gte(lhs_val: Value, rhs_val: Value) -> Value {
1784 match lhs_val {
1785 Value::BigInt(val) => {
1786 let rhs = rhs_val.unwrap_big_int();
1787 Value::Bool(val >= rhs)
1788 }
1789 Value::Int(val) => {
1790 let rhs = rhs_val.unwrap_int();
1791 Value::Bool(val >= rhs)
1792 }
1793 Value::Double(val) => {
1794 let rhs = rhs_val.unwrap_double();
1795 Value::Bool(val >= rhs)
1796 }
1797 _ => panic!("value doesn't support binop gte"),
1798 }
1799}
1800
1801fn eval_binop_lt(lhs_val: Value, rhs_val: Value) -> Value {
1802 match lhs_val {
1803 Value::BigInt(val) => {
1804 let rhs = rhs_val.unwrap_big_int();
1805 Value::Bool(val < rhs)
1806 }
1807 Value::Int(val) => {
1808 let rhs = rhs_val.unwrap_int();
1809 Value::Bool(val < rhs)
1810 }
1811 Value::Double(val) => {
1812 let rhs = rhs_val.unwrap_double();
1813 Value::Bool(val < rhs)
1814 }
1815 _ => panic!("value doesn't support binop lt"),
1816 }
1817}
1818
1819fn eval_binop_lte(lhs_val: Value, rhs_val: Value) -> Value {
1820 match lhs_val {
1821 Value::BigInt(val) => {
1822 let rhs = rhs_val.unwrap_big_int();
1823 Value::Bool(val <= rhs)
1824 }
1825 Value::Int(val) => {
1826 let rhs = rhs_val.unwrap_int();
1827 Value::Bool(val <= rhs)
1828 }
1829 Value::Double(val) => {
1830 let rhs = rhs_val.unwrap_double();
1831 Value::Bool(val <= rhs)
1832 }
1833 _ => panic!("value doesn't support binop lte"),
1834 }
1835}
1836
1837fn eval_binop_mod(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1838 match lhs_val {
1839 Value::BigInt(val) => {
1840 let rhs = rhs_val.unwrap_big_int();
1841 if rhs == BigInt::from(0) {
1842 Err(Error::DivZero(rhs_span))
1843 } else {
1844 Ok(Value::BigInt(val % rhs))
1845 }
1846 }
1847 Value::Int(val) => {
1848 let rhs = rhs_val.unwrap_int();
1849 if rhs == 0 {
1850 Err(Error::DivZero(rhs_span))
1851 } else {
1852 Ok(Value::Int(val.wrapping_rem(rhs)))
1853 }
1854 }
1855 Value::Double(val) => {
1856 let rhs = rhs_val.unwrap_double();
1857 if rhs == 0.0 {
1858 Err(Error::DivZero(rhs_span))
1859 } else {
1860 Ok(Value::Double(val % rhs))
1861 }
1862 }
1863 _ => panic!("value should support mod"),
1864 }
1865}
1866
1867fn eval_binop_mul(lhs_val: Value, rhs_val: Value) -> Value {
1868 match lhs_val {
1869 Value::BigInt(val) => {
1870 let rhs = rhs_val.unwrap_big_int();
1871 Value::BigInt(val * rhs)
1872 }
1873 Value::Int(val) => {
1874 let rhs = rhs_val.unwrap_int();
1875 Value::Int(val.wrapping_mul(rhs))
1876 }
1877 Value::Double(val) => {
1878 let rhs = rhs_val.unwrap_double();
1879 Value::Double(val * rhs)
1880 }
1881 _ => panic!("value should support mul"),
1882 }
1883}
1884
1885fn eval_binop_orb(lhs_val: Value, rhs_val: Value) -> Value {
1886 match lhs_val {
1887 Value::BigInt(val) => {
1888 let rhs = rhs_val.unwrap_big_int();
1889 Value::BigInt(val | rhs)
1890 }
1891 Value::Int(val) => {
1892 let rhs = rhs_val.unwrap_int();
1893 Value::Int(val | rhs)
1894 }
1895 _ => panic!("value type does not support orb"),
1896 }
1897}
1898
1899fn eval_binop_shl(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1900 Ok(match lhs_val {
1901 Value::BigInt(val) => {
1902 let rhs = rhs_val.unwrap_int();
1903 if rhs > 0 {
1904 Value::BigInt(val << rhs)
1905 } else {
1906 Value::BigInt(val >> rhs.abs())
1907 }
1908 }
1909 Value::Int(val) => {
1910 let rhs = rhs_val.unwrap_int();
1911 Value::Int(if rhs > 0 {
1912 let shift: u32 = rhs.try_into().or(Err(Error::IntTooLarge(rhs, rhs_span)))?;
1913 val.checked_shl(shift)
1914 .ok_or(Error::IntTooLarge(rhs, rhs_span))?
1915 } else {
1916 let shift: u32 = rhs
1917 .checked_neg()
1918 .ok_or(Error::IntTooLarge(rhs, rhs_span))?
1919 .try_into()
1920 .or(Err(Error::IntTooLarge(rhs, rhs_span)))?;
1921 val.checked_shr(shift)
1922 .ok_or(Error::IntTooLarge(rhs, rhs_span))?
1923 })
1924 }
1925 _ => panic!("value should support shl"),
1926 })
1927}
1928
1929fn eval_binop_shr(lhs_val: Value, rhs_val: Value, rhs_span: PackageSpan) -> Result<Value, Error> {
1930 Ok(match lhs_val {
1931 Value::BigInt(val) => {
1932 let rhs = rhs_val.unwrap_int();
1933 if rhs > 0 {
1934 Value::BigInt(val >> rhs)
1935 } else {
1936 Value::BigInt(val << rhs.abs())
1937 }
1938 }
1939 Value::Int(val) => {
1940 let rhs = rhs_val.unwrap_int();
1941 Value::Int(if rhs > 0 {
1942 let shift: u32 = rhs.try_into().or(Err(Error::IntTooLarge(rhs, rhs_span)))?;
1943 val.checked_shr(shift)
1944 .ok_or(Error::IntTooLarge(rhs, rhs_span))?
1945 } else {
1946 let shift: u32 = rhs
1947 .checked_neg()
1948 .ok_or(Error::IntTooLarge(rhs, rhs_span))?
1949 .try_into()
1950 .or(Err(Error::IntTooLarge(rhs, rhs_span)))?;
1951 val.checked_shl(shift)
1952 .ok_or(Error::IntTooLarge(rhs, rhs_span))?
1953 })
1954 }
1955 _ => panic!("value should support shr"),
1956 })
1957}
1958
1959fn eval_binop_sub(lhs_val: Value, rhs_val: Value) -> Value {
1960 match lhs_val {
1961 Value::BigInt(val) => {
1962 let rhs = rhs_val.unwrap_big_int();
1963 Value::BigInt(val - rhs)
1964 }
1965 Value::Double(val) => {
1966 let rhs = rhs_val.unwrap_double();
1967 Value::Double(val - rhs)
1968 }
1969 Value::Int(val) => {
1970 let rhs = rhs_val.unwrap_int();
1971 Value::Int(val.wrapping_sub(rhs))
1972 }
1973 _ => panic!("value is not subtractable"),
1974 }
1975}
1976
1977fn eval_binop_xorb(lhs_val: Value, rhs_val: Value) -> Value {
1978 match lhs_val {
1979 Value::BigInt(val) => {
1980 let rhs = rhs_val.unwrap_big_int();
1981 Value::BigInt(val ^ rhs)
1982 }
1983 Value::Int(val) => {
1984 let rhs = rhs_val.unwrap_int();
1985 Value::Int(val ^ rhs)
1986 }
1987 _ => panic!("value type does not support xorb"),
1988 }
1989}
1990
1991fn follow_field_path(mut value: Value, path: &[usize]) -> Option<Value> {
1992 for &index in path {
1993 let Value::Tuple(items) = value else {
1994 return None;
1995 };
1996 value = items[index].clone();
1997 }
1998 Some(value)
1999}
2000
2001fn update_field_path(record: &Value, path: &[usize], replace: &Value) -> Option<Value> {
2002 match (record, path) {
2003 (_, []) => Some(replace.clone()),
2004 (Value::Tuple(items), &[next_index, ..]) if next_index < items.len() => {
2005 let update = |(index, item)| {
2006 if index == next_index {
2007 update_field_path(item, &path[1..], replace)
2008 } else {
2009 Some(item.clone())
2010 }
2011 };
2012
2013 let items: Option<_> = items.iter().enumerate().map(update).collect();
2014 Some(Value::Tuple(items?))
2015 }
2016 _ => None,
2017 }
2018}
2019
2020fn is_updatable_in_place(env: &Env, expr: &Expr) -> (bool, bool) {
2021 match &expr.kind {
2022 ExprKind::Var(Res::Local(id), _) => match env.get(*id) {
2023 Some(var) => match &var.value {
2024 Value::Array(var) => (true, Rc::weak_count(var) + Rc::strong_count(var) == 1),
2025 _ => (false, false),
2026 },
2027 _ => (false, false),
2028 },
2029 _ => (false, false),
2030 }
2031}
2032
2033fn is_counting_call(name: &str) -> bool {
2034 matches!(
2035 name,
2036 "StartCountingOperation"
2037 | "StopCountingOperation"
2038 | "StartCountingFunction"
2039 | "StopCountingFunction"
2040 | "StartCountingQubits"
2041 | "StopCountingQubits"
2042 )
2043}
2044
2045fn make_counting_key(id: StoreItemId, functor: FunctorApp) -> CallableCountKey {
2046 (id, functor.adjoint, functor.controlled > 0)
2047}
2048
2049#[derive(Default)]
2050struct QubitCounter {
2051 seen: FxHashSet<usize>,
2052 count: i64,
2053}
2054
2055impl QubitCounter {
2056 fn allocated(&mut self, qubit: usize) {
2057 if self.seen.insert(qubit) {
2058 self.count += 1;
2059 }
2060 }
2061
2062 fn into_count(self) -> i64 {
2063 self.count
2064 }
2065}