Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions frontend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
//! Quon frontend — lexer, parser, type checker, and AST→IR lowering.
//!
//! Stub implementations in this crate are expanded in issues #5–#16.

#![allow(
dead_code,
clippy::new_without_default,
clippy::large_enum_variant,
// `TypeError` carries resolved `Ty`s (with symbolic `Circuit`/`QReg` dimensions) for
Expand Down
8 changes: 1 addition & 7 deletions frontend/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ pub struct LoweringCtx<'c> {
struct FuncMeta {
depth: DepthExpr,
clifford: bool,
in_qubits: i64,
out_qubits: i64,
}

struct GateSpec {
Expand Down Expand Up @@ -149,16 +147,14 @@ impl<'c> LoweringCtx<'c> {
&& let Ok(ret_ty @ Ty::Circuit { .. }) = self.checker.resolve_type(ret)
{
if params.is_empty() {
let Ty::Circuit { n, m, d, c } = ret_ty else {
let Ty::Circuit { n: _, m: _, d, c } = ret_ty else {
unreachable!("matched above");
};
self.func_meta.insert(
name.0.clone(),
FuncMeta {
depth: d,
clifford: matches!(c, CliffordClass::Clifford),
in_qubits: const_width(&n, "in_qubits")?,
out_qubits: const_width(&m, "out_qubits")?,
},
);
Arc::make_mut(&mut self.bodies).insert(name.0.clone(), body.clone());
Expand Down Expand Up @@ -287,8 +283,6 @@ impl<'c> LoweringCtx<'c> {
FuncMeta {
depth: depth.clone(),
clifford,
in_qubits,
out_qubits,
},
);
Arc::make_mut(&mut self.bodies).insert(name.to_string(), body.clone());
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/specialized_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

use std::collections::HashMap;

#[cfg(test)]
use chumsky::span::SimpleSpan;
use quon_core::DepthExpr;
use thiserror::Error;
Expand Down Expand Up @@ -390,6 +391,7 @@ fn literal_usize(expr: &Expr) -> Option<usize> {
}
}

#[cfg(test)]
fn no_span() -> SimpleSpan {
SimpleSpan::from(0..0)
}
Expand Down
30 changes: 0 additions & 30 deletions frontend/src/typecheck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1419,15 +1419,6 @@ impl TypeChecker {
}
}

/// Evaluate a `Nat` expression to a concrete `u64`, when it is closed and literal.
/// Symbolic naturals are rejected — the classical fragment has no value-dependent types.
fn eval_nat(&self, n: &Sp<NatExpr>) -> Result<u64, TypeError> {
eval_nat(&n.0).ok_or(TypeError::Unsupported {
construct: "symbolic Nat in type",
span: n.1,
})
}

/// Convert a surface depth annotation to a [`DepthExpr`]. Best-effort for the classical
/// fragment: literals/vars/`+`/`*` map directly; richer forms defer to issue #13.
/// Rejects `CodeFamily` tags and `F: CodeFamily` params in Nat position.
Expand Down Expand Up @@ -2301,27 +2292,6 @@ fn eval_angle(e: &Sp<Expr>) -> Option<f64> {
}
}

fn eval_nat(n: &NatExpr) -> Option<u64> {
Some(match n {
NatExpr::Lit(v) => *v,
NatExpr::Var(_) | NatExpr::Hole => return None,
NatExpr::Add(a, b) => eval_nat(&a.0)?.checked_add(eval_nat(&b.0)?)?,
NatExpr::Mul(a, b) => eval_nat(&a.0)?.checked_mul(eval_nat(&b.0)?)?,
NatExpr::Sub(a, b) => eval_nat(&a.0)?.saturating_sub(eval_nat(&b.0)?),
NatExpr::Div(a, b) => {
let d = eval_nat(&b.0)?;
if d == 0 {
return None;
}
eval_nat(&a.0)? / d
}
NatExpr::Exp(a, b) => {
let exp = u32::try_from(eval_nat(&b.0)?).ok()?;
eval_nat(&a.0)?.checked_pow(exp)?
}
})
}

fn nat_to_depth(n: &NatExpr) -> Option<DepthExpr> {
Some(match n {
NatExpr::Lit(v) => DepthExpr::Nat(*v),
Expand Down
12 changes: 10 additions & 2 deletions frontend/tests/support/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// Shared test support: normalize every span in an AST to 0..0 so that structural
// equality (derived PartialEq) compares trees while ignoring source positions.

#![allow(dead_code)]

use frontend::ast::*;
use frontend::lexer::{SimpleSpan, Sp};

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn z() -> SimpleSpan {
(0..0).into()
}
Expand All @@ -18,16 +17,19 @@ macro_rules! go {
}};
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
pub fn strip_decls(decls: &mut [Sp<Decl>]) {
for d in decls.iter_mut() {
go!(d, strip_decl);
}
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_sp_name(n: &mut Sp<Name>) {
n.1 = z();
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_decl(d: &mut Decl) {
match d {
Decl::Fn {
Expand Down Expand Up @@ -65,6 +67,7 @@ fn strip_decl(d: &mut Decl) {
}
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_nat(n: &mut NatExpr) {
match n {
NatExpr::Lit(_) | NatExpr::Var(_) | NatExpr::Hole => {}
Expand All @@ -79,6 +82,7 @@ fn strip_nat(n: &mut NatExpr) {
}
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_ty(t: &mut Type) {
match t {
Type::Qubit
Expand Down Expand Up @@ -122,6 +126,7 @@ fn strip_ty(t: &mut Type) {
}
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_pat(p: &mut Pat) {
match p {
Pat::Wildcard | Pat::Var(_) | Pat::Lit(_) => {}
Expand All @@ -133,6 +138,7 @@ fn strip_pat(p: &mut Pat) {
}
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_stmt(s: &mut Stmt) {
match s {
Stmt::Bind { pat, rhs } | Stmt::Let { pat, rhs } => {
Expand All @@ -143,6 +149,7 @@ fn strip_stmt(s: &mut Stmt) {
}
}

#[allow(dead_code)] // shared test helper — not every test uses every strip helper
fn strip_expr(e: &mut Expr) {
match e {
Expr::Int(_) | Expr::Float(_) | Expr::Bool(_) | Expr::Unit | Expr::Var(_) => {}
Expand Down Expand Up @@ -239,6 +246,7 @@ fn strip_expr(e: &mut Expr) {
}

/// Parse source into a span-stripped AST, panicking with diagnostics on failure.
#[allow(dead_code)] // shared test helper — not every test uses every strip helper
pub fn parse_stripped(src: &str) -> Vec<Sp<Decl>> {
let mut decls = frontend::parse_program(src).expect("parse failed");
strip_decls(&mut decls);
Expand Down
4 changes: 0 additions & 4 deletions mlir_bridge/src/emit/openqasm3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ fn is_rotation(name: &str) -> bool {
struct Reifier<'t> {
qubits: HashMap<usize, QubitId>,
bits: HashMap<usize, BitId>,
num_qubits: usize,
num_bits: usize,
next_qubit: usize,
next_bit: usize,
native: HashSet<String>,
Expand Down Expand Up @@ -337,8 +335,6 @@ pub fn reify(module: &Module, target: &BackendTarget) -> Result<Program, EmitErr
let mut reifier = Reifier {
qubits: HashMap::new(),
bits: HashMap::new(),
num_qubits,
num_bits,
next_qubit: 0,
next_bit: 0,
native: target
Expand Down
4 changes: 0 additions & 4 deletions mlir_bridge/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
//! MLIR bridge — Melior wrappers, dialect registration, passes, and emitter.
//!
//! Stub implementations in this crate are expanded in issues #4–#27.

#![allow(dead_code)]

pub mod circ_extract;
pub mod diagnostics;
Expand Down
12 changes: 5 additions & 7 deletions mlir_bridge/src/passes/dynamic_linearity_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@ struct QubitDef<'c> {
kind: DefKind,
}

struct QubitUse<'c> {
struct QubitUse {
user_name: String,
location: Location<'c>,
is_measure: bool,
}

Expand Down Expand Up @@ -79,7 +78,7 @@ fn is_measure_op(name: &str) -> bool {
pub fn check_dynamic_linearity<'c>(region: RegionRef<'c, '_>) -> Diagnostics<'c> {
let mut diagnostics = Diagnostics::new();
let mut defs = Vec::new();
let mut uses: HashMap<usize, Vec<QubitUse<'c>>> = HashMap::new();
let mut uses: HashMap<usize, Vec<QubitUse>> = HashMap::new();
collect_dynamic_scope(region, &mut defs, &mut uses, &mut diagnostics);
check_scope(&defs, &uses, &mut diagnostics);
diagnostics
Expand All @@ -88,7 +87,7 @@ pub fn check_dynamic_linearity<'c>(region: RegionRef<'c, '_>) -> Diagnostics<'c>
fn collect_dynamic_scope<'c>(
region: RegionRef<'c, '_>,
defs: &mut Vec<QubitDef<'c>>,
uses: &mut HashMap<usize, Vec<QubitUse<'c>>>,
uses: &mut HashMap<usize, Vec<QubitUse>>,
diagnostics: &mut Diagnostics<'c>,
) {
let mut block = region.first_block();
Expand Down Expand Up @@ -150,7 +149,7 @@ fn collect_dynamic_scope<'c>(

fn check_scope<'c>(
defs: &[QubitDef<'c>],
uses: &HashMap<usize, Vec<QubitUse<'c>>>,
uses: &HashMap<usize, Vec<QubitUse>>,
diagnostics: &mut Diagnostics<'c>,
) {
for def in defs {
Expand Down Expand Up @@ -185,14 +184,13 @@ fn check_scope<'c>(

fn record_qubit_operands<'c: 'a, 'a, O: OperationLike<'c, 'a>>(
operation: &O,
uses: &mut HashMap<usize, Vec<QubitUse<'c>>>,
uses: &mut HashMap<usize, Vec<QubitUse>>,
) {
let name = op_name(operation);
for operand in operation.operands() {
if is_qubit(&operand) {
uses.entry(value_key(&operand)).or_default().push(QubitUse {
user_name: name.clone(),
location: operand.location(),
is_measure: is_measure_op(&name),
});
}
Expand Down
4 changes: 0 additions & 4 deletions mlir_bridge/src/passes/native_gate_decomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ fn read_f64_attr<'c: 'a, 'a, O: OperationLike<'c, 'a>>(operation: &O, key: &str)
FloatAttribute::try_from(value).ok().map(|f| f.value())
}

fn value_key<'a>(value: &impl ValueLike<'a>) -> usize {
value.to_raw().ptr as usize
}

fn native_gate_names(target: &FixedTarget) -> Vec<String> {
target.native_gates.iter().map(|g| g.name.clone()).collect()
}
Expand Down
16 changes: 16 additions & 0 deletions mlir_bridge/tests/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,60 +21,72 @@ use mlir_bridge::dialect::quantum_dynamic as qd;
use quon_core::DepthExpr;

/// A context with the `quantum.circ` dialect registered.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn context() -> Context {
let context = Context::new();
qc::register_dialect(&context);
context
}

/// A context with both `quantum.circ` and `quantum.dynamic` registered.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn dynamic_context() -> Context {
let context = Context::new();
qc::register_dialect(&context);
qd::register_dialect(&context);
context
}

#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn i64_attr(context: &Context, value: i64) -> Attribute<'_> {
IntegerAttribute::new(IntegerType::new(context, 64).into(), value).into()
}

#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn str_attr<'c>(context: &'c Context, value: &str) -> Attribute<'c> {
StringAttribute::new(context, value).into()
}

#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn bool_attr(context: &Context, value: bool) -> Attribute<'_> {
BoolAttribute::new(context, value).into()
}

#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn i32_attr(context: &Context, value: i32) -> Attribute<'_> {
IntegerAttribute::new(IntegerType::new(context, 32).into(), i64::from(value)).into()
}

#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn f64_attr(context: &Context, value: f64) -> Attribute<'_> {
let float_type = Type::parse(context, "f64").unwrap_or_else(|| Type::none(context));
FloatAttribute::new(context, float_type, value).into()
}

#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn f32_attr(context: &Context, value: f64) -> Attribute<'_> {
let float_type = Type::parse(context, "f32").unwrap_or_else(|| Type::none(context));
FloatAttribute::new(context, float_type, value).into()
}

/// A serialized depth attribute (a string, per ADR-0002).
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn depth_attr<'c>(context: &'c Context, depth: &DepthExpr) -> Attribute<'c> {
str_attr(context, &depth.to_sexpr())
}

/// A detached block whose arguments source SSA values of the requested types.
/// Keep the returned block alive for as long as the values are used.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn scratch_block<'c>(types: &[Type<'c>], location: Location<'c>) -> Block<'c> {
let args: Vec<(Type, Location)> = types.iter().map(|t| (*t, location)).collect();
Block::new(&args)
}

/// Appends a verified `quantum.dynamic.alloc` op producing one fresh
/// `!quantum.qubit` (issue #401 — replaces the unregistered `test.qubit`).
/// Appends a foreign op to `body` that produces one `!quantum.qubit`.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn append_foreign_qubit<'c: 'a, 'a, B: BlockLike<'c, 'a>>(
context: &'c Context,
body: &B,
Expand All @@ -88,12 +100,14 @@ pub fn append_foreign_qubit<'c: 'a, 'a, B: BlockLike<'c, 'a>>(
}

/// The module's top-level region — the linearity scope for dynamic tests.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn module_region<'c>(module: &'c Module<'c>) -> melior::ir::RegionRef<'c, 'c> {
module.as_operation().region(0).expect("module region")
}

/// Builds an op in MLIR's generic form **without** running the dialect verifier.
/// Used to construct deliberately-malformed ops for verifier tests.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn generic_op<'c>(
context: &'c Context,
name: &str,
Expand All @@ -117,13 +131,15 @@ pub fn generic_op<'c>(
}

/// A region containing a single empty block — a minimal well-formed body.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn empty_body() -> Region<'static> {
let region = Region::new();
region.append_block(Block::new(&[]));
region
}

/// Builds `func @main(%q: !qubit) -> !qubit { %r = gate "H" %q; return %r }`.
#[allow(dead_code)] // shared test helper — not every integration test uses every helper
pub fn bell_like_module(context: &Context) -> Module<'_> {
let location = Location::unknown(context);
let qubit = qc::qubit_type(context);
Expand Down
Loading
Loading