cqlib_core/circuit/control_flow/mod.rs
1// This code is part of Cqlib.
2//
3// (C) Copyright China Telecom Quantum Group 2026
4//
5// This code is licensed under the Apache License, Version 2.0. You may
6// obtain a copy of this license in the LICENSE.txt file in the root directory
7// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8//
9// Any modifications or derivative works of this code must retain this
10// copyright notice, and modified files need to carry a notice indicating
11// that they have been altered from the originals.
12
13//! Expression-based classical control-flow IR.
14//!
15//! This module defines the third layer of cqlib's dynamic-circuit classical
16//! control model: structured control-flow operations that consume typed,
17//! side-effect-free classical expressions.
18//!
19//! The model is intentionally split into three layers:
20//!
21//! 1. Runtime classical values and storage are defined by
22//! [`crate::circuit::classical`]. Those types identify circuit-local
23//! classical storage and value types.
24//! 2. Classical expressions are defined by
25//! [`ClassicalExpr`](crate::circuit::ClassicalExpr).
26//! Expressions are strongly typed and have no side effects. They only read
27//! runtime classical variables, combine literals, cast explicitly, compare
28//! values, select between values, or extract/pack bits.
29//! 3. Control-flow operations are defined in this module by
30//! [`ClassicalControlOp`] and the concrete operation structs. They consume
31//! [`ClassicalExpr`](crate::circuit::ClassicalExpr) values to decide which
32//! structured body executes.
33//!
34//! This module is IR only. It does not allocate classical storage, execute a
35//! circuit, or lower control flow to backend instructions.
36//!
37//! # Core Concepts
38//!
39//! [`ClassicalExpr`](crate::circuit::ClassicalExpr) represents a runtime classical computation. It has a
40//! static [`crate::circuit::ClassicalType`] and can report the classical
41//! variables and immutable values it reads. The expression layer does not write
42//! storage, measure qubits, branch, or loop.
43//!
44//! [`ControlBody`] owns the operations inside a structured control-flow region.
45//! A body is a sequence of ordinary circuit [`crate::circuit::Operation`] values
46//! that belongs to an operation such as [`IfOp`], [`WhileOp`], [`ForOp`], or
47//! [`SwitchOp`].
48//!
49//! [`ClassicalControlOp`] is the sum type for structured classical control
50//! operations:
51//!
52//! - [`IfOp`] executes a `then` body, and optionally an `else` body, when a
53//! boolean condition is evaluated at runtime.
54//! - [`WhileOp`] repeats a body while a boolean condition remains true.
55//! - [`ForOp`] models an unsigned half-open runtime range loop,
56//! `[start, stop)`, with an explicit unsigned loop variable and step.
57//! - [`SwitchOp`] selects one body by matching an unsigned expression against
58//! exact case values. Cases do not fall through.
59//! - [`ClassicalControlOp::Break`] exits the nearest enclosing loop or switch.
60//! - [`ClassicalControlOp::Continue`] advances the nearest enclosing loop.
61//!
62//! Conditions for [`IfOp`] and [`WhileOp`] must have type `Bool`; measured
63//! `Bit` values must be explicitly cast with
64//! [`ClassicalExpr::bit_to_bool`](crate::circuit::ClassicalExpr::bit_to_bool).
65//! Ordered comparisons are restricted to `UInt` expressions. Bit-vector to
66//! integer interpretation is explicit through
67//! [`ClassicalExpr::bit_vec_to_uint`](crate::circuit::ClassicalExpr::bit_vec_to_uint),
68//! preserving the rule that bit index `0` is the least-significant bit.
69//!
70//! # Resource Queries
71//!
72//! Control-flow IR nodes expose lightweight dependency queries:
73//!
74//! - `classical_var_reads()` returns classical variables read by controlling
75//! expressions.
76//! - `classical_value_reads()` returns immutable classical values read by
77//! controlling expressions.
78//! - `classical_writes()` currently reports direct writes introduced by the
79//! control operation itself, such as a [`ForOp`] loop variable.
80//! - `used_qubits()` reports qubits referenced directly by structured bodies.
81//!
82//! These methods are structural summaries for validation, remapping, and future
83//! lowering passes. They are not a complete data-flow analysis for nested
84//! dynamic-circuit execution.
85//!
86//! Classical handles are circuit-local. When circuits are composed, classical
87//! variables and values from the source circuit are copied into the destination
88//! circuit's classical tables and every expression/control body reference is
89//! remapped to the new local ID.
90//!
91//! # Examples
92//!
93//! Build a boolean condition from a measured bit-like variable:
94//!
95//! ```text
96//! bit_var: ClassicalVar<Bit>
97//!
98//! bit_expr = ClassicalExpr::var(bit_var)
99//! condition = ClassicalExpr::bit_to_bool(bit_expr)
100//! if_op = IfOp::new(condition, then_body, else_body)
101//! ```
102//!
103//! Build an unsigned comparison for a loop or branch condition:
104//!
105//! ```text
106//! counter: ClassicalVar<UInt(8)>
107//!
108//! lhs = ClassicalExpr::var(counter)
109//! rhs = ClassicalExpr::uint_literal(8, 10)
110//! condition = ClassicalExpr::lt(lhs, rhs)
111//! while_op = WhileOp::new(condition, body)
112//! ```
113//!
114//! Build a switch over an unsigned runtime expression:
115//!
116//! ```text
117//! state: ClassicalVar<UInt(2)>
118//!
119//! target = ClassicalExpr::var(state)
120//! cases = [
121//! SwitchCase::new(0, zero_body),
122//! SwitchCase::new(1, one_body),
123//! SwitchCase::new(2, two_body),
124//! ]
125//! switch = SwitchOp::new(target, cases, default_body)
126//! ```
127//!
128//! Build a runtime `for` loop:
129//!
130//! ```text
131//! i: ClassicalVar<UInt(8)>
132//!
133//! start = ClassicalExpr::uint_literal(8, 0)
134//! stop = ClassicalExpr::uint_literal(8, 16)
135//! step = ClassicalExpr::uint_literal(8, 1)
136//! for_op = ForOp::new(i, start, stop, step, body)
137//! ```
138//!
139//! # Design Boundaries
140//!
141//! This module deliberately does not define post-selection or runtime
142//! assertions as first-class control-flow operations. Post-selection belongs to
143//! execution/result filtering semantics, while assertions belong to diagnostics
144//! or verification. They can be added later as separate IR families once their
145//! backend behavior and failure model are specified.
146
147mod body;
148mod control_op;
149mod for_op;
150mod if_op;
151mod switch_op;
152mod validation;
153mod while_op;
154
155pub use body::ControlBody;
156pub use control_op::{ClassicalControlKind, ClassicalControlOp};
157pub use for_op::ForOp;
158pub use if_op::IfOp;
159pub use switch_op::{SwitchCase, SwitchOp};
160pub(crate) use validation::{validate_for_types, validate_switch};
161pub use while_op::WhileOp;