From fbf2a0a7c59167c0037a168dcb5d07bc33fd7fb0 Mon Sep 17 00:00:00 2001 From: Mine Starks <> Date: Wed, 4 Mar 2026 11:20:29 -0800 Subject: [PATCH 1/3] Eliminate redundant round-trip casts in OpenQASM-to-Q# compilation --- .../qsc_openqasm_compiler/src/compiler.rs | 71 ++++++- .../src/tests/expression.rs | 1 + .../src/tests/expression/roundtrip_cast.rs | 179 ++++++++++++++++++ 3 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs diff --git a/source/compiler/qsc_openqasm_compiler/src/compiler.rs b/source/compiler/qsc_openqasm_compiler/src/compiler.rs index 82442bfc78..0d010762e4 100644 --- a/source/compiler/qsc_openqasm_compiler/src/compiler.rs +++ b/source/compiler/qsc_openqasm_compiler/src/compiler.rs @@ -1885,6 +1885,17 @@ impl QasmCompiler { } fn compile_cast_expr(&mut self, cast: &Cast) -> qsast::Expr { + // Optimization: eliminate round-trip casts (e.g. Bit → UInt(1) → Bit) + let inner = unwrap_parens(&cast.expr); + if let semast::ExprKind::Cast(inner_cast) = inner.kind.as_ref() + && Self::maps_to_same_qsharp_type(&cast.ty, &inner_cast.expr.ty) + { + let result = self.compile_expr(&inner_cast.expr); + // Wrap in parens to preserve grouping, since the removed casts + // acted as implicit grouping delimiters in the output. + return wrap_expr_in_parens(result, cast.span); + } + let expr = self.compile_expr(&cast.expr); let cast_expr = match cast.expr.ty { qsc_openqasm_parser::semantic::types::Type::Bit(_) => { @@ -2073,7 +2084,7 @@ impl QasmCompiler { /// Pushes an unsupported error with the supplied message. pub fn push_unsupported_error_message>(&mut self, message: S, span: Span) { - let kind = CompilerErrorKind::NotSupported(message.as_ref().to_string(), span); + let kind = unsupported_err(message, span); self.push_compiler_error(kind); } @@ -2478,6 +2489,21 @@ impl QasmCompiler { &mut self, ty: &qsc_openqasm_parser::semantic::types::Type, span: Span, + ) -> crate::types::Type { + let mut errors = Vec::new(); + let mapped = Self::semantic_type_for_qsharp_type(ty, span, &mut errors); + for error in errors { + self.push_compiler_error(error); + } + mapped + } + + /// Mapping from an `OpenQASM` semantic type to its Q# equivalent. + /// Returns the mapped type and any errors that would have been pushed. + fn semantic_type_for_qsharp_type( + ty: &qsc_openqasm_parser::semantic::types::Type, + span: Span, + errs: &mut Vec, ) -> crate::types::Type { use qsc_openqasm_parser::semantic::types::Type; if ty.is_array() @@ -2486,7 +2512,7 @@ impl QasmCompiler { Some(qsc_openqasm_parser::semantic::types::ArrayDimensions::Err) ) { - self.push_unsupported_error_message("arrays with more than 7 dimensions", span); + errs.push(unsupported_err("arrays with more than 7 dimensions", span)); return crate::types::Type::Err; } @@ -2495,7 +2521,7 @@ impl QasmCompiler { Type::Bit(_) => crate::types::Type::Result(is_const), Type::Qubit => crate::types::Type::Qubit, Type::HardwareQubit => { - self.push_unsupported_error_message("hardware qubits", span); + errs.push(unsupported_err("hardware qubits", span)); crate::types::Type::Err } Type::QubitArray(_) => { @@ -2517,11 +2543,11 @@ impl QasmCompiler { Type::Complex(_, _) => crate::types::Type::Complex(is_const), Type::Bool(_) => crate::types::Type::Bool(is_const), Type::Duration(_) => { - self.push_unsupported_error_message("duration type values", span); + errs.push(unsupported_err("duration type values", span)); crate::types::Type::Err } Type::Stretch(_) => { - self.push_unsupported_error_message("stretch type values", span); + errs.push(unsupported_err("stretch type values", span)); crate::types::Type::Err } Type::BitArray(_, _) => { @@ -2546,12 +2572,12 @@ impl QasmCompiler { } Type::StaticArrayRef(array_ref) if array_ref.is_mutable => { let msg = format!("mutable array references `{ty}`"); - self.push_unsupported_error_message(msg, span); + errs.push(unsupported_err(msg, span)); crate::types::Type::Err } Type::DynArrayRef(array_ref) if array_ref.is_mutable => { let msg = format!("mutable array references `{ty}`"); - self.push_unsupported_error_message(msg, span); + errs.push(unsupported_err(msg, span)); crate::types::Type::Err } Type::Gate(cargs, qargs) => crate::types::Type::Gate(*cargs, *qargs), @@ -2571,15 +2597,16 @@ impl QasmCompiler { }; let args = args .iter() - .map(|arg| self.map_semantic_type_to_qsharp_type(arg, Span::default())) + .map(|arg| Self::semantic_type_for_qsharp_type(arg, Span::default(), errs)) .collect::>(); - let return_ty = self.map_semantic_type_to_qsharp_type(return_ty, Span::default()); + let return_ty = + Self::semantic_type_for_qsharp_type(return_ty, Span::default(), errs); crate::types::Type::Callable(kind, args.into(), return_ty.into()) } Type::Err => crate::types::Type::Err, _ => { let msg = format!("converting `{ty}` to Q# type"); - self.push_unimplemented_error_message(msg, span); + errs.push(CompilerErrorKind::Unimplemented(msg, span)); crate::types::Type::Err } } @@ -2618,6 +2645,17 @@ impl QasmCompiler { } } + /// Returns `true` if both `OpenQASM` types map to the same Q# type without errors. + fn maps_to_same_qsharp_type( + a: &qsc_openqasm_parser::semantic::types::Type, + b: &qsc_openqasm_parser::semantic::types::Type, + ) -> bool { + let mut errs = Vec::new(); + let ty_a = Self::semantic_type_for_qsharp_type(a, Span::default(), &mut errs); + let ty_b = Self::semantic_type_for_qsharp_type(b, Span::default(), &mut errs); + errs.is_empty() && ty_a == ty_b + } + fn get_argument_validation_stmts( args: &[(&String, qsast::Ty, Span, &Type)], ) -> Vec { @@ -2648,3 +2686,16 @@ impl QasmCompiler { Some(body) } } + +/// Follows `ExprKind::Paren` chains, returning the innermost expression. +fn unwrap_parens(expr: &semast::Expr) -> &semast::Expr { + let mut current = expr; + while let semast::ExprKind::Paren(inner) = current.kind.as_ref() { + current = inner; + } + current +} + +fn unsupported_err>(message: S, span: Span) -> CompilerErrorKind { + CompilerErrorKind::NotSupported(message.as_ref().to_string(), span) +} diff --git a/source/compiler/qsc_openqasm_compiler/src/tests/expression.rs b/source/compiler/qsc_openqasm_compiler/src/tests/expression.rs index bb73b061e7..eca5161f11 100644 --- a/source/compiler/qsc_openqasm_compiler/src/tests/expression.rs +++ b/source/compiler/qsc_openqasm_compiler/src/tests/expression.rs @@ -24,4 +24,5 @@ mod implicit_cast_from_complex; mod implicit_cast_from_float; mod implicit_cast_from_int; mod indexed; +mod roundtrip_cast; mod unary; diff --git a/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs b/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs new file mode 100644 index 0000000000..f21838abec --- /dev/null +++ b/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::tests::check_qasm_to_qsharp as check; +use expect_test::expect; + +//=========================================== +// Round-trips through Result eliminated +//=========================================== + +#[test] +fn bit_xor_no_redundant_cast() { + let source = " + bit a; + bit b; + bit c = a ^ b; + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = Zero; + mutable b = Zero; + mutable c = Std.OpenQASM.Convert.IntAsResult(Std.OpenQASM.Convert.ResultAsInt(a) ^^^ Std.OpenQASM.Convert.ResultAsInt(b)); + "#]], + ); +} + +#[test] +fn bit_and_no_redundant_cast() { + let source = " + bit a; + bit b; + bit c = a & b; + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = Zero; + mutable b = Zero; + mutable c = Std.OpenQASM.Convert.IntAsResult(Std.OpenQASM.Convert.ResultAsInt(a) &&& Std.OpenQASM.Convert.ResultAsInt(b)); + "#]], + ); +} + +#[test] +fn bit_or_no_redundant_cast() { + let source = " + bit a; + bit b; + bit c = a | b; + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = Zero; + mutable b = Zero; + mutable c = Std.OpenQASM.Convert.IntAsResult(Std.OpenQASM.Convert.ResultAsInt(a) ||| Std.OpenQASM.Convert.ResultAsInt(b)); + "#]], + ); +} + +//=========================================== +// Explicit round-trips also eliminated +//=========================================== + +#[test] +fn explicit_int_to_bit_to_int() { + let source = " + int a; + int(bit(a)); + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = 0; + (a); + "#]], + ); +} + +#[test] +fn explicit_bit_to_bool_to_bit() { + let source = " + bit a; + bit(bool(a)); + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = Zero; + (a); + "#]], + ); +} + +//=========================================== +// Non-elimination (different Q# types) +//=========================================== + +#[test] +fn int_to_bit_to_bigint_not_eliminated() { + let source = " + int[32] a; + int[128](bit(a)); + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = 0; + Std.OpenQASM.Convert.ResultAsBigInt(Std.OpenQASM.Convert.IntAsResult(a)); + "#]], + ); +} + +//=========================================== +// Paren preservation +//=========================================== + +#[test] +fn paren_wrapped_roundtrip() { + let source = " + int a; + int((bit(a))); + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = 0; + (a); + "#]], + ); +} + +#[test] +fn paren_roundtrip_in_larger_expr() { + let source = " + int a = 1; + int b = 2; + int c = 3; + int d = int((bit(a + b))) * c; + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = 1; + mutable b = 2; + mutable c = 3; + mutable d = (a + b) * c; + "#]], + ); +} + +#[test] +fn no_paren_roundtrip_in_larger_expr() { + let source = " + int a = 1; + int b = 2; + int c = 3; + int d = int(bit(a + b)) * c; + "; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + mutable a = 1; + mutable b = 2; + mutable c = 3; + mutable d = (a + b) * c; + "#]], + ); +} From 0e554d5c87c06fbcd1f7dce4248ad08713a03c0c Mon Sep 17 00:00:00 2001 From: Mine Starks <> Date: Wed, 4 Mar 2026 11:57:05 -0800 Subject: [PATCH 2/3] account for differing constness --- .../qsc_openqasm_compiler/src/compiler.rs | 3 ++- .../src/tests/expression/roundtrip_cast.rs | 27 +++++++++++++++++++ .../qsc_openqasm_compiler/src/types.rs | 22 +++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/source/compiler/qsc_openqasm_compiler/src/compiler.rs b/source/compiler/qsc_openqasm_compiler/src/compiler.rs index 0d010762e4..dbd7d5138e 100644 --- a/source/compiler/qsc_openqasm_compiler/src/compiler.rs +++ b/source/compiler/qsc_openqasm_compiler/src/compiler.rs @@ -2646,6 +2646,7 @@ impl QasmCompiler { } /// Returns `true` if both `OpenQASM` types map to the same Q# type without errors. + /// Ignores const qualifiers, since constness does not affect the Q# representation. fn maps_to_same_qsharp_type( a: &qsc_openqasm_parser::semantic::types::Type, b: &qsc_openqasm_parser::semantic::types::Type, @@ -2653,7 +2654,7 @@ impl QasmCompiler { let mut errs = Vec::new(); let ty_a = Self::semantic_type_for_qsharp_type(a, Span::default(), &mut errs); let ty_b = Self::semantic_type_for_qsharp_type(b, Span::default(), &mut errs); - errs.is_empty() && ty_a == ty_b + errs.is_empty() && ty_a.without_const() == ty_b.without_const() } fn get_argument_validation_stmts( diff --git a/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs b/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs index f21838abec..b5370b1c98 100644 --- a/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs +++ b/source/compiler/qsc_openqasm_compiler/src/tests/expression/roundtrip_cast.rs @@ -177,3 +177,30 @@ fn no_paren_roundtrip_in_larger_expr() { "#]], ); } + +#[test] +fn bit_array_xor_original_repro() { + let source = r#" + include "stdgates.inc"; + qubit[4] q; + bit[1] r1; + r1[0] = measure q[0]; + bit[1] r2; + r2[0] = measure q[1]; + if ((r1^r2)!=0) cx q[2],q[3]; + "#; + check( + source, + &expect![[r#" + import Std.OpenQASM.Intrinsic.*; + borrow q = Qubit[4]; + mutable r1 = [Zero]; + set r1[0] = Std.Intrinsic.M(q[0]); + mutable r2 = [Zero]; + set r2[0] = Std.Intrinsic.M(q[1]); + if (Std.OpenQASM.Convert.ResultArrayAsIntBE(r1) ^^^ Std.OpenQASM.Convert.ResultArrayAsIntBE(r2)) != 0 { + cx(q[2], q[3]); + }; + "#]], + ); +} diff --git a/source/compiler/qsc_openqasm_compiler/src/types.rs b/source/compiler/qsc_openqasm_compiler/src/types.rs index 5267e50542..10bea73214 100644 --- a/source/compiler/qsc_openqasm_compiler/src/types.rs +++ b/source/compiler/qsc_openqasm_compiler/src/types.rs @@ -46,6 +46,28 @@ pub enum Type { Err, } +impl Type { + /// Returns the same type with the const qualifier set to `false`. + pub fn without_const(self) -> Self { + match self { + Self::Angle(_) => Self::Angle(false), + Self::Bool(_) => Self::Bool(false), + Self::BigInt(_) => Self::BigInt(false), + Self::Complex(_) => Self::Complex(false), + Self::Int(_) => Self::Int(false), + Self::Double(_) => Self::Double(false), + Self::Result(_) => Self::Result(false), + Self::BoolArray(d, _) => Self::BoolArray(d, false), + Self::BigIntArray(d, _) => Self::BigIntArray(d, false), + Self::IntArray(d, _) => Self::IntArray(d, false), + Self::ComplexArray(d, _) => Self::ComplexArray(d, false), + Self::AngleArray(d, _) => Self::AngleArray(d, false), + Self::ResultArray(d, _) => Self::ResultArray(d, false), + other => other, + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum CallableKind { /// A function. From 111ddf24e3977390ed0ce6a68600ca6b5a882acf Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:50:18 -0800 Subject: [PATCH 3/3] Remove const bool flag from `qsc_openqasm_compiler::types::Type` (#3004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `Type` enum in `qsc_openqasm_compiler` carried a `bool` const qualifier on most variants (e.g. `Int(bool)`, `Result(bool)`, `BoolArray(ArrayDimensions, bool)`). Since Q# has no const bindings, this flag was never meaningful in the Q# type representation and only added noise — requiring a dedicated `without_const()` method just to normalize types for equality comparisons. ## Changes - **`types.rs`**: Strip the `bool` const parameter from all `Type` variants; remove `without_const()`. - **`compiler.rs`**: - `semantic_type_for_qsharp_type`: no longer extracts or forwards `is_const` into `Type` construction. - `make_qsharp_array_ty`: removes hardcoded `false` const args. - `maps_to_same_qsharp_type`: simplifies to direct `==` comparison (the note about ignoring const qualifiers is now moot). - **`ast_builder.rs`**: `map_qsharp_type_to_ast_ty` updated to match new variant shapes. ```rust // Before pub enum Type { Int(bool), Result(bool), ResultArray(ArrayDimensions, bool), // ... } // After pub enum Type { Int, Result, ResultArray(ArrayDimensions), // ... } ``` Constness is still read from the OpenQASM parser symbol (`symbol.ty.is_const()`) where it matters — to decide Q# declaration mutability (`let` vs `mutable`) — it just no longer flows into the intermediate `Type` representation. --- 🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. [Learn more about Advanced Security.](https://gh.io/cca-advanced-security) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: minestarks <16928427+minestarks@users.noreply.github.com> --- .../qsc_openqasm_compiler/src/ast_builder.rs | 26 +++---- .../qsc_openqasm_compiler/src/compiler.rs | 42 +++++------ .../qsc_openqasm_compiler/src/types.rs | 74 +++++++------------ 3 files changed, 59 insertions(+), 83 deletions(-) diff --git a/source/compiler/qsc_openqasm_compiler/src/ast_builder.rs b/source/compiler/qsc_openqasm_compiler/src/ast_builder.rs index 9e0cb1e70b..d26dc633e2 100644 --- a/source/compiler/qsc_openqasm_compiler/src/ast_builder.rs +++ b/source/compiler/qsc_openqasm_compiler/src/ast_builder.rs @@ -1182,25 +1182,25 @@ pub(crate) fn build_unary_op_expr(op: ast::UnOp, expr: ast::Expr, prefix_span: S pub(crate) fn map_qsharp_type_to_ast_ty(output_ty: &crate::types::Type, span: Span) -> Ty { let mut ty = match output_ty { - crate::types::Type::Angle(_) => build_angle_ty_ident(), - crate::types::Type::Result(_) => build_path_ident_ty("Result"), + crate::types::Type::Angle => build_angle_ty_ident(), + crate::types::Type::Result => build_path_ident_ty("Result"), crate::types::Type::Qubit => build_path_ident_ty("Qubit"), - crate::types::Type::BigInt(_) => build_path_ident_ty("BigInt"), - crate::types::Type::Int(_) => build_path_ident_ty("Int"), - crate::types::Type::Double(_) => build_path_ident_ty("Double"), - crate::types::Type::Complex(_) => build_complex_ty_ident(), - crate::types::Type::Bool(_) => build_path_ident_ty("Bool"), - crate::types::Type::ResultArray(dims, _) => build_array_type_name("Result", *dims), + crate::types::Type::BigInt => build_path_ident_ty("BigInt"), + crate::types::Type::Int => build_path_ident_ty("Int"), + crate::types::Type::Double => build_path_ident_ty("Double"), + crate::types::Type::Complex => build_complex_ty_ident(), + crate::types::Type::Bool => build_path_ident_ty("Bool"), + crate::types::Type::ResultArray(dims) => build_array_type_name("Result", *dims), crate::types::Type::QubitArray(dims) => build_array_type_name("Qubit", *dims), - crate::types::Type::BigIntArray(dims, _) => build_array_type_name("BigInt", *dims), - crate::types::Type::IntArray(dims, _) => build_array_type_name("Int", *dims), + crate::types::Type::BigIntArray(dims) => build_array_type_name("BigInt", *dims), + crate::types::Type::IntArray(dims) => build_array_type_name("Int", *dims), crate::types::Type::DoubleArray(dims) => build_array_type_name("Double", *dims), - crate::types::Type::BoolArray(dims, _) => build_array_type_name("Bool", *dims), - crate::types::Type::ComplexArray(dims, _) => { + crate::types::Type::BoolArray(dims) => build_array_type_name("Bool", *dims), + crate::types::Type::ComplexArray(dims) => { let ty = build_complex_ty_ident(); wrap_array_ty_by_dims(*dims, ty) } - crate::types::Type::AngleArray(dims, _) => { + crate::types::Type::AngleArray(dims) => { let ty = build_angle_ty_ident(); wrap_array_ty_by_dims(*dims, ty) } diff --git a/source/compiler/qsc_openqasm_compiler/src/compiler.rs b/source/compiler/qsc_openqasm_compiler/src/compiler.rs index dbd7d5138e..2b0e571a50 100644 --- a/source/compiler/qsc_openqasm_compiler/src/compiler.rs +++ b/source/compiler/qsc_openqasm_compiler/src/compiler.rs @@ -329,7 +329,7 @@ impl QasmCompiler { if let Some(inputs) = &input { for input in inputs { let qsharp_ty = self.map_semantic_type_to_qsharp_type(&input.ty, input.ty_span); - if matches!(qsharp_ty, crate::types::Type::Angle(..)) { + if matches!(qsharp_ty, crate::types::Type::Angle) { let message = "use `float` types for passing input, using `angle` types".to_string(); let kind = CompilerErrorKind::NotSupported(message, input.span); @@ -504,8 +504,8 @@ impl QasmCompiler { .map(|symbol| { let qsharp_ty = self.map_semantic_type_to_qsharp_type(&symbol.ty, symbol.ty_span); - if matches!(qsharp_ty, crate::types::Type::Angle(..)) { - crate::types::Type::Double(symbol.ty.is_const()) + if matches!(qsharp_ty, crate::types::Type::Angle) { + crate::types::Type::Double } else { qsharp_ty } @@ -751,7 +751,7 @@ impl QasmCompiler { rhs_span, rhs_span, rhs_span, - &crate::types::Type::ResultArray(crate::types::ArrayDimensions::One, false), + &crate::types::Type::ResultArray(crate::types::ArrayDimensions::One), temp_var_stmt_init_expr, ); let temp_var_expr = build_path_ident_expr("bitarray", rhs_span, rhs_span); @@ -2516,9 +2516,8 @@ impl QasmCompiler { return crate::types::Type::Err; } - let is_const = ty.is_const(); match ty { - Type::Bit(_) => crate::types::Type::Result(is_const), + Type::Bit(_) => crate::types::Type::Result, Type::Qubit => crate::types::Type::Qubit, Type::HardwareQubit => { errs.push(unsupported_err("hardware qubits", span)); @@ -2530,18 +2529,18 @@ impl QasmCompiler { Type::Int(width, _) | Type::UInt(width, _) => { if let Some(width) = width { if *width > 64 { - crate::types::Type::BigInt(is_const) + crate::types::Type::BigInt } else { - crate::types::Type::Int(is_const) + crate::types::Type::Int } } else { - crate::types::Type::Int(is_const) + crate::types::Type::Int } } - Type::Float(_, _) => crate::types::Type::Double(is_const), - Type::Angle(_, _) => crate::types::Type::Angle(is_const), - Type::Complex(_, _) => crate::types::Type::Complex(is_const), - Type::Bool(_) => crate::types::Type::Bool(is_const), + Type::Float(_, _) => crate::types::Type::Double, + Type::Angle(_, _) => crate::types::Type::Angle, + Type::Complex(_, _) => crate::types::Type::Complex, + Type::Bool(_) => crate::types::Type::Bool, Type::Duration(_) => { errs.push(unsupported_err("duration type values", span)); crate::types::Type::Err @@ -2551,7 +2550,7 @@ impl QasmCompiler { crate::types::Type::Err } Type::BitArray(_, _) => { - crate::types::Type::ResultArray(crate::types::ArrayDimensions::One, is_const) + crate::types::Type::ResultArray(crate::types::ArrayDimensions::One) } Type::Array(array) if !matches!( @@ -2619,13 +2618,13 @@ impl QasmCompiler { match base_ty { qsc_openqasm_parser::semantic::types::ArrayBaseType::Duration => unreachable!(), qsc_openqasm_parser::semantic::types::ArrayBaseType::Bool => { - crate::types::Type::BoolArray(dims, false) + crate::types::Type::BoolArray(dims) } qsc_openqasm_parser::semantic::types::ArrayBaseType::Angle(_) => { - crate::types::Type::AngleArray(dims, false) + crate::types::Type::AngleArray(dims) } qsc_openqasm_parser::semantic::types::ArrayBaseType::Complex(_) => { - crate::types::Type::ComplexArray(dims, false) + crate::types::Type::ComplexArray(dims) } qsc_openqasm_parser::semantic::types::ArrayBaseType::Float(_) => { crate::types::Type::DoubleArray(dims) @@ -2634,19 +2633,18 @@ impl QasmCompiler { | qsc_openqasm_parser::semantic::types::ArrayBaseType::UInt(width) => { if let Some(width) = width { if *width > 64 { - crate::types::Type::BigIntArray(dims, false) + crate::types::Type::BigIntArray(dims) } else { - crate::types::Type::IntArray(dims, false) + crate::types::Type::IntArray(dims) } } else { - crate::types::Type::IntArray(dims, false) + crate::types::Type::IntArray(dims) } } } } /// Returns `true` if both `OpenQASM` types map to the same Q# type without errors. - /// Ignores const qualifiers, since constness does not affect the Q# representation. fn maps_to_same_qsharp_type( a: &qsc_openqasm_parser::semantic::types::Type, b: &qsc_openqasm_parser::semantic::types::Type, @@ -2654,7 +2652,7 @@ impl QasmCompiler { let mut errs = Vec::new(); let ty_a = Self::semantic_type_for_qsharp_type(a, Span::default(), &mut errs); let ty_b = Self::semantic_type_for_qsharp_type(b, Span::default(), &mut errs); - errs.is_empty() && ty_a.without_const() == ty_b.without_const() + errs.is_empty() && ty_a == ty_b } fn get_argument_validation_stmts( diff --git a/source/compiler/qsc_openqasm_compiler/src/types.rs b/source/compiler/qsc_openqasm_compiler/src/types.rs index 10bea73214..7411a75d9f 100644 --- a/source/compiler/qsc_openqasm_compiler/src/types.rs +++ b/source/compiler/qsc_openqasm_compiler/src/types.rs @@ -20,24 +20,24 @@ impl Complex { #[derive(Debug, Clone, Default, PartialEq, Eq)] pub enum Type { - Angle(bool), - Bool(bool), - BigInt(bool), - Complex(bool), - Int(bool), - Double(bool), + Angle, + Bool, + BigInt, + Complex, + Int, + Double, Qubit, - Result(bool), + Result, Tuple(Vec), Range, - BoolArray(ArrayDimensions, bool), - BigIntArray(ArrayDimensions, bool), - IntArray(ArrayDimensions, bool), + BoolArray(ArrayDimensions), + BigIntArray(ArrayDimensions), + IntArray(ArrayDimensions), DoubleArray(ArrayDimensions), - ComplexArray(ArrayDimensions, bool), - AngleArray(ArrayDimensions, bool), + ComplexArray(ArrayDimensions), + AngleArray(ArrayDimensions), QubitArray(ArrayDimensions), - ResultArray(ArrayDimensions, bool), + ResultArray(ArrayDimensions), /// # cargs, # qargs Gate(u32, u32), /// kind, args, return ty @@ -46,28 +46,6 @@ pub enum Type { Err, } -impl Type { - /// Returns the same type with the const qualifier set to `false`. - pub fn without_const(self) -> Self { - match self { - Self::Angle(_) => Self::Angle(false), - Self::Bool(_) => Self::Bool(false), - Self::BigInt(_) => Self::BigInt(false), - Self::Complex(_) => Self::Complex(false), - Self::Int(_) => Self::Int(false), - Self::Double(_) => Self::Double(false), - Self::Result(_) => Self::Result(false), - Self::BoolArray(d, _) => Self::BoolArray(d, false), - Self::BigIntArray(d, _) => Self::BigIntArray(d, false), - Self::IntArray(d, _) => Self::IntArray(d, false), - Self::ComplexArray(d, _) => Self::ComplexArray(d, false), - Self::AngleArray(d, _) => Self::AngleArray(d, false), - Self::ResultArray(d, _) => Self::ResultArray(d, false), - other => other, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum CallableKind { /// A function. @@ -155,15 +133,15 @@ impl From for ArrayDimensions { impl Display for Type { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - Type::Angle(_) => write!(f, "Angle"), - Type::Bool(_) => write!(f, "bool"), - Type::BigInt(_) => write!(f, "BigInt"), - Type::Complex(_) => write!(f, "Complex"), - Type::Int(_) => write!(f, "Int"), - Type::Double(_) => write!(f, "Double"), + Type::Angle => write!(f, "Angle"), + Type::Bool => write!(f, "bool"), + Type::BigInt => write!(f, "BigInt"), + Type::Complex => write!(f, "Complex"), + Type::Int => write!(f, "Int"), + Type::Double => write!(f, "Double"), Type::Qubit => write!(f, "Qubit"), Type::Range => write!(f, "Range"), - Type::Result(_) => write!(f, "Result"), + Type::Result => write!(f, "Result"), Type::Tuple(types) => { write!(f, "(")?; for (i, ty) in types.iter().enumerate() { @@ -174,14 +152,14 @@ impl Display for Type { } write!(f, ")") } - Type::BoolArray(dim, _) => write!(f, "bool{dim}"), - Type::BigIntArray(dim, _) => write!(f, "BigInt{dim}"), - Type::IntArray(dim, _) => write!(f, "Int{dim}"), + Type::BoolArray(dim) => write!(f, "bool{dim}"), + Type::BigIntArray(dim) => write!(f, "BigInt{dim}"), + Type::IntArray(dim) => write!(f, "Int{dim}"), Type::DoubleArray(dim) => write!(f, "Double{dim}"), - Type::ComplexArray(dim, _) => write!(f, "Complex{dim}"), - Type::AngleArray(dim, _) => write!(f, "Angle{dim}"), + Type::ComplexArray(dim) => write!(f, "Complex{dim}"), + Type::AngleArray(dim) => write!(f, "Angle{dim}"), Type::QubitArray(dim) => write!(f, "Qubit{dim}"), - Type::ResultArray(dim, _) => write!(f, "Result{dim}"), + Type::ResultArray(dim) => write!(f, "Result{dim}"), Type::Callable(kind, args, return_type) => { write!(f, "Callable({kind}, {args:?}, {return_type})") }