1use std::str::FromStr;
4use std::sync::{Arc, Weak};
5
6use itertools::Itertools;
7use lazy_static::lazy_static;
8
9use crate::extension::const_fold::fold_out_row;
10use crate::extension::simple_op::{
11 MakeExtensionOp, MakeOpDef, MakeRegisteredOp, OpLoadError, try_from_name,
12};
13use crate::extension::{
14 ConstFold, ExtensionId, OpDef, SignatureError, SignatureFunc, TypeDefBound,
15};
16use crate::ops::OpName;
17use crate::ops::constant::{CustomCheckFailure, CustomConst, ValueName};
18use crate::ops::{NamedOp, Value};
19use crate::types::type_param::{TypeArg, TypeParam};
20use crate::types::{
21 CustomType, FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature, SumType, Term, Type,
22 TypeBound, TypeName, TypeRV, TypeRow, TypeRowRV,
23};
24use crate::utils::sorted_consts;
25use crate::{Extension, type_row};
26
27use strum::{EnumIter, EnumString, IntoStaticStr};
28
29use super::ExtensionRegistry;
30use super::resolution::{ExtensionResolutionError, WeakExtensionRegistry, resolve_type_extensions};
31
32mod unwrap_builder;
33
34pub use unwrap_builder::UnwrapBuilder;
35
36pub mod generic;
38
39pub const PRELUDE_ID: ExtensionId = ExtensionId::new_unchecked("prelude");
41pub const VERSION: semver::Version = semver::Version::new(0, 2, 1);
43lazy_static! {
44 pub static ref PRELUDE: Arc<Extension> = {
46 Extension::new_arc(PRELUDE_ID, VERSION, |prelude, extension_ref| {
47
48 let string_type: Type = string_custom_type(extension_ref).into();
55 let usize_type: Type = usize_custom_t(extension_ref).into();
56 let error_type: CustomType = error_custom_type(extension_ref);
57
58 prelude
59 .add_type(
60 TypeName::new_inline("usize"),
61 vec![],
62 "usize".into(),
63 TypeDefBound::copyable(),
64 extension_ref,
65 )
66 .unwrap();
67 prelude.add_type(
68 STRING_TYPE_NAME,
69 vec![],
70 "string".into(),
71 TypeDefBound::copyable(),
72 extension_ref,
73 )
74 .unwrap();
75 prelude.add_op(
76 PRINT_OP_ID,
77 "Print the string to standard output".to_string(),
78 Signature::new(vec![string_type.clone()], type_row![]),
79 extension_ref,
80 )
81 .unwrap();
82 prelude
83 .add_type(
84 TypeName::new_inline("qubit"),
85 vec![],
86 "qubit".into(),
87 TypeDefBound::any(),
88 extension_ref,
89 )
90 .unwrap();
91 prelude
92 .add_type(
93 ERROR_TYPE_NAME,
94 vec![],
95 "Simple opaque error type.".into(),
96 TypeDefBound::copyable(),
97 extension_ref,
98 )
99 .unwrap();
100 prelude
101 .add_op(
102 MAKE_ERROR_OP_ID,
103 "Create an error value".to_string(),
104 Signature::new(vec![usize_type, string_type], vec![error_type.clone().into()]),
105 extension_ref,
106 )
107 .unwrap();
108 prelude
109 .add_op(
110 PANIC_OP_ID,
111 "Panic with input error".to_string(),
112 PolyFuncTypeRV::new(
113 [TypeParam::new_list_type(TypeBound::Linear), TypeParam::new_list_type(TypeBound::Linear)],
114 FuncValueType::new(
115 vec![TypeRV::new_extension(error_type.clone()), TypeRV::new_row_var_use(0, TypeBound::Linear)],
116 vec![TypeRV::new_row_var_use(1, TypeBound::Linear)],
117 ),
118 ),
119 extension_ref,
120 )
121 .unwrap();
122 prelude
123 .add_op(
124 EXIT_OP_ID,
125 "Exit with input error".to_string(),
126 PolyFuncTypeRV::new(
127 [TypeParam::new_list_type(TypeBound::Linear), TypeParam::new_list_type(TypeBound::Linear)],
128 FuncValueType::new(
129 vec![TypeRV::new_extension(error_type), TypeRV::new_row_var_use(0, TypeBound::Linear)],
130 vec![TypeRV::new_row_var_use(1, TypeBound::Linear)],
131 ),
132 ),
133 extension_ref,
134 )
135 .unwrap();
136
137 TupleOpDef::load_all_ops(prelude, extension_ref).unwrap();
138 NoopDef.add_to_extension(prelude, extension_ref).unwrap();
139 BarrierDef.add_to_extension(prelude, extension_ref).unwrap();
140 generic::LoadNatDef.add_to_extension(prelude, extension_ref).unwrap();
141 })
142 };
143
144 pub static ref PRELUDE_REGISTRY: ExtensionRegistry = ExtensionRegistry::new([PRELUDE.clone()]);
146}
147
148pub(crate) fn usize_custom_t(extension_ref: &Weak<Extension>) -> CustomType {
149 CustomType::new(
150 TypeName::new_inline("usize"),
151 vec![],
152 PRELUDE_ID,
153 TypeBound::Copyable,
154 extension_ref,
155 )
156}
157
158pub(crate) fn qb_custom_t(extension_ref: &Weak<Extension>) -> CustomType {
159 CustomType::new(
160 TypeName::new_inline("qubit"),
161 vec![],
162 PRELUDE_ID,
163 TypeBound::Linear,
164 extension_ref,
165 )
166}
167
168#[must_use]
170pub fn qb_t() -> Type {
171 qb_custom_t(&Arc::downgrade(&PRELUDE)).into()
172}
173#[must_use]
175pub fn usize_t() -> Type {
176 usize_custom_t(&Arc::downgrade(&PRELUDE)).into()
177}
178#[must_use]
180pub fn bool_t() -> Type {
181 Type::new_unit_sum(2)
182}
183
184pub const MAKE_ERROR_OP_ID: OpName = OpName::new_inline("MakeError");
188
189pub const PANIC_OP_ID: OpName = OpName::new_inline("panic");
202
203pub const EXIT_OP_ID: OpName = OpName::new_inline("exit");
216
217pub const STRING_TYPE_NAME: TypeName = TypeName::new_inline("string");
219
220fn string_custom_type(extension_ref: &Weak<Extension>) -> CustomType {
225 CustomType::new(
226 STRING_TYPE_NAME,
227 vec![],
228 PRELUDE_ID,
229 TypeBound::Copyable,
230 extension_ref,
231 )
232}
233
234#[must_use]
236pub fn string_type() -> Type {
237 string_custom_type(&Arc::downgrade(&PRELUDE)).into()
238}
239
240#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
241pub struct ConstString(String);
243
244impl ConstString {
245 #[must_use]
247 pub fn new(value: String) -> Self {
248 Self(value)
249 }
250
251 #[must_use]
253 pub fn value(&self) -> &str {
254 &self.0
255 }
256}
257
258#[typetag::serde]
259impl CustomConst for ConstString {
260 fn name(&self) -> ValueName {
261 format!("ConstString({:?})", self.0).into()
262 }
263
264 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
265 crate::ops::constant::downcast_equal_consts(self, other)
266 }
267
268 fn get_type(&self) -> Type {
269 string_type()
270 }
271}
272
273pub const PRINT_OP_ID: OpName = OpName::new_inline("print");
275
276fn error_custom_type(extension_ref: &Weak<Extension>) -> CustomType {
281 CustomType::new(
282 ERROR_TYPE_NAME,
283 vec![],
284 PRELUDE_ID,
285 TypeBound::Copyable,
286 extension_ref,
287 )
288}
289
290#[must_use]
292pub fn error_type() -> Type {
293 error_custom_type(&Arc::downgrade(&PRELUDE)).into()
294}
295
296pub const ERROR_TYPE_NAME: TypeName = TypeName::new_inline("error");
298
299pub fn sum_with_error(ty: impl Into<TypeRowRV>) -> SumType {
301 either_type(error_type(), ty)
302}
303
304#[inline]
306pub fn option_type(ty: impl Into<TypeRowRV>) -> SumType {
307 either_type(TypeRow::new(), ty)
308}
309
310#[inline]
315pub fn either_type(ty_left: impl Into<TypeRowRV>, ty_right: impl Into<TypeRowRV>) -> SumType {
316 SumType::new([ty_left.into(), ty_right.into()])
317}
318
319#[must_use]
323pub fn const_some(value: Value) -> Value {
324 const_some_tuple([value])
325}
326
327pub fn const_some_tuple(values: impl IntoIterator<Item = Value>) -> Value {
333 const_right_tuple(TypeRow::new(), values)
334}
335
336pub fn const_none(ty: impl Into<TypeRowRV>) -> Value {
340 const_left_tuple([], ty)
341}
342
343pub fn const_left(value: Value, ty_right: impl Into<TypeRowRV>) -> Value {
349 const_left_tuple([value], ty_right)
350}
351
352pub fn const_left_tuple(
358 values: impl IntoIterator<Item = Value>,
359 ty_right: impl Into<TypeRowRV>,
360) -> Value {
361 let values = values.into_iter().collect_vec();
362 let types: TypeRowRV = values
363 .iter()
364 .map(|v| TypeRV::from(v.get_type()))
365 .collect_vec()
366 .into();
367 let typ = either_type(types, ty_right);
368 Value::sum(0, values, typ).unwrap()
369}
370
371pub fn const_right(ty_left: impl Into<TypeRowRV>, value: Value) -> Value {
377 const_right_tuple(ty_left, [value])
378}
379
380pub fn const_right_tuple(
386 ty_left: impl Into<TypeRowRV>,
387 values: impl IntoIterator<Item = Value>,
388) -> Value {
389 let values = values.into_iter().collect_vec();
390 let types: TypeRowRV = values
391 .iter()
392 .map(|v| TypeRV::from(v.get_type()))
393 .collect_vec()
394 .into();
395 let typ = either_type(ty_left, types);
396 Value::sum(1, values, typ).unwrap()
397}
398
399pub fn const_ok(value: Value, ty_fail: impl Into<TypeRowRV>) -> Value {
403 const_right(ty_fail, value)
404}
405
406pub fn const_ok_tuple(
410 values: impl IntoIterator<Item = Value>,
411 ty_fail: impl Into<TypeRowRV>,
412) -> Value {
413 const_right_tuple(ty_fail, values)
414}
415
416pub fn const_fail(value: Value, ty_ok: impl Into<TypeRowRV>) -> Value {
420 const_left(value, ty_ok)
421}
422
423pub fn const_fail_tuple(
427 values: impl IntoIterator<Item = Value>,
428 ty_ok: impl Into<TypeRowRV>,
429) -> Value {
430 const_left_tuple(values, ty_ok)
431}
432
433#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
434pub struct ConstUsize(u64);
436
437impl ConstUsize {
438 #[must_use]
440 pub fn new(value: u64) -> Self {
441 Self(value)
442 }
443
444 #[must_use]
446 pub fn value(&self) -> u64 {
447 self.0
448 }
449}
450
451#[typetag::serde]
452impl CustomConst for ConstUsize {
453 fn name(&self) -> ValueName {
454 format!("ConstUsize({})", self.0).into()
455 }
456
457 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
458 crate::ops::constant::downcast_equal_consts(self, other)
459 }
460
461 fn get_type(&self) -> Type {
462 usize_t()
463 }
464}
465
466#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
467pub struct ConstError {
471 pub signal: u32,
473 pub message: String,
475}
476
477pub const DEFAULT_ERROR_SIGNAL: u32 = 1;
479
480impl ConstError {
481 pub fn new(signal: u32, message: impl ToString) -> Self {
483 Self {
484 signal,
485 message: message.to_string(),
486 }
487 }
488
489 pub fn new_default_signal(message: impl ToString) -> Self {
493 Self::new(DEFAULT_ERROR_SIGNAL, message)
494 }
495 pub fn as_either(self, ty_ok: impl Into<TypeRowRV>) -> Value {
500 const_fail(self.into(), ty_ok)
501 }
502}
503
504#[typetag::serde]
505impl CustomConst for ConstError {
506 fn name(&self) -> ValueName {
507 format!("ConstError({}, {:?})", self.signal, self.message).into()
508 }
509
510 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
511 crate::ops::constant::downcast_equal_consts(self, other)
512 }
513
514 fn get_type(&self) -> Type {
515 error_type()
516 }
517}
518
519impl FromStr for ConstError {
520 type Err = ();
521
522 fn from_str(s: &str) -> Result<Self, Self::Err> {
523 Ok(Self::new_default_signal(s))
524 }
525}
526
527impl From<String> for ConstError {
528 fn from(s: String) -> Self {
529 Self::new_default_signal(s)
530 }
531}
532
533#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
534pub struct ConstExternalSymbol {
536 pub symbol: String,
538 pub typ: Type,
540 pub constant: bool,
542}
543
544impl ConstExternalSymbol {
545 pub fn new(symbol: impl Into<String>, typ: impl Into<Type>, constant: bool) -> Self {
547 Self {
548 symbol: symbol.into(),
549 typ: typ.into(),
550 constant,
551 }
552 }
553}
554
555impl PartialEq<dyn CustomConst> for ConstExternalSymbol {
556 fn eq(&self, other: &dyn CustomConst) -> bool {
557 self.equal_consts(other)
558 }
559}
560
561#[typetag::serde]
562impl CustomConst for ConstExternalSymbol {
563 fn name(&self) -> ValueName {
564 format!("@{}", &self.symbol).into()
565 }
566
567 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
568 crate::ops::constant::downcast_equal_consts(self, other)
569 }
570
571 fn get_type(&self) -> Type {
572 self.typ.clone()
573 }
574
575 fn update_extensions(
576 &mut self,
577 extensions: &WeakExtensionRegistry,
578 ) -> Result<(), ExtensionResolutionError> {
579 resolve_type_extensions(&mut self.typ, extensions)
580 }
581
582 fn validate(&self) -> Result<(), CustomCheckFailure> {
583 if self.symbol.is_empty() {
584 Err(CustomCheckFailure::Message(
585 "External symbol name is empty.".into(),
586 ))
587 } else {
588 Ok(())
589 }
590 }
591}
592
593#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, EnumIter, IntoStaticStr, EnumString)]
595#[allow(missing_docs)]
596#[non_exhaustive]
597pub enum TupleOpDef {
598 MakeTuple,
599 UnpackTuple,
600}
601
602impl ConstFold for TupleOpDef {
603 fn fold(
604 &self,
605 _type_args: &[TypeArg],
606 consts: &[(crate::IncomingPort, Value)],
607 ) -> crate::extension::ConstFoldResult {
608 match self {
609 TupleOpDef::MakeTuple => {
610 fold_out_row([Value::tuple(sorted_consts(consts).into_iter().cloned())])
611 }
612 TupleOpDef::UnpackTuple => {
613 let c = &consts.first()?.1;
614 let Some(vs) = c.as_tuple() else {
615 panic!("This op always takes a Tuple input.");
616 };
617 fold_out_row(vs.iter().cloned())
618 }
619 }
620 }
621}
622
623impl MakeOpDef for TupleOpDef {
624 fn opdef_id(&self) -> OpName {
625 <&'static str>::from(self).into()
626 }
627
628 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
629 let rv = TypeRV::new_row_var_use(0, TypeBound::Linear);
630 let tuple_type = TypeRV::new_tuple(vec![rv.clone()]);
631
632 let param = TypeParam::new_list_type(TypeBound::Linear);
633 match self {
634 TupleOpDef::MakeTuple => {
635 PolyFuncTypeRV::new([param], FuncValueType::new(rv, tuple_type))
636 }
637 TupleOpDef::UnpackTuple => {
638 PolyFuncTypeRV::new([param], FuncValueType::new(tuple_type, rv))
639 }
640 }
641 .into()
642 }
643
644 fn description(&self) -> String {
645 match self {
646 TupleOpDef::MakeTuple => "MakeTuple operation",
647 TupleOpDef::UnpackTuple => "UnpackTuple operation",
648 }
649 .to_string()
650 }
651
652 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
653 try_from_name(op_def.name(), op_def.extension_id())
654 }
655
656 fn extension(&self) -> ExtensionId {
657 PRELUDE_ID.clone()
658 }
659
660 fn extension_ref(&self) -> Weak<Extension> {
661 Arc::downgrade(&PRELUDE)
662 }
663
664 fn post_opdef(&self, def: &mut OpDef) {
665 def.set_constant_folder(*self);
666 }
667}
668#[derive(Debug, Clone, Default, PartialEq, Eq)]
670#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
671#[non_exhaustive]
672pub struct MakeTuple(pub TypeRow);
673
674impl MakeTuple {
675 #[must_use]
677 pub fn new(tys: TypeRow) -> Self {
678 Self(tys)
679 }
680}
681
682impl MakeExtensionOp for MakeTuple {
683 fn op_id(&self) -> OpName {
684 TupleOpDef::MakeTuple.opdef_id()
685 }
686
687 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
688 where
689 Self: Sized,
690 {
691 let def = TupleOpDef::from_def(ext_op.def())?;
692 if def != TupleOpDef::MakeTuple {
693 return Err(OpLoadError::NotMember(ext_op.unqualified_id().to_string()))?;
694 }
695 let [TypeArg::List(elems)] = ext_op.args() else {
696 return Err(SignatureError::InvalidTypeArgs)?;
697 };
698 let tys: Result<Vec<Type>, _> = elems
699 .iter()
700 .map(|a| match a {
701 TypeArg::Runtime(ty) => Ok(ty.clone()),
702 _ => Err(SignatureError::InvalidTypeArgs),
703 })
704 .collect();
705 Ok(Self(tys?.into()))
706 }
707
708 fn type_args(&self) -> Vec<TypeArg> {
709 vec![Term::new_list(self.0.iter().map(|t| t.clone().into()))]
710 }
711}
712
713impl MakeRegisteredOp for MakeTuple {
714 fn extension_id(&self) -> ExtensionId {
715 PRELUDE_ID.clone()
716 }
717
718 fn extension_ref(&self) -> Weak<Extension> {
719 Arc::downgrade(&PRELUDE)
720 }
721}
722
723#[derive(Debug, Clone, Default, PartialEq, Eq)]
725#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
726#[non_exhaustive]
727pub struct UnpackTuple(pub TypeRow);
728
729impl UnpackTuple {
730 #[must_use]
732 pub fn new(tys: TypeRow) -> Self {
733 Self(tys)
734 }
735}
736
737impl MakeExtensionOp for UnpackTuple {
738 fn op_id(&self) -> OpName {
739 TupleOpDef::UnpackTuple.opdef_id()
740 }
741
742 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
743 where
744 Self: Sized,
745 {
746 let def = TupleOpDef::from_def(ext_op.def())?;
747 if def != TupleOpDef::UnpackTuple {
748 return Err(OpLoadError::NotMember(ext_op.unqualified_id().to_string()))?;
749 }
750 let [Term::List(elems)] = ext_op.args() else {
751 return Err(SignatureError::InvalidTypeArgs)?;
752 };
753 let tys: Result<Vec<Type>, _> = elems
754 .iter()
755 .map(|a| match a {
756 Term::Runtime(ty) => Ok(ty.clone()),
757 _ => Err(SignatureError::InvalidTypeArgs),
758 })
759 .collect();
760 Ok(Self(tys?.into()))
761 }
762
763 fn type_args(&self) -> Vec<Term> {
764 vec![Term::new_list(self.0.iter().map(|t| t.clone().into()))]
765 }
766}
767
768impl MakeRegisteredOp for UnpackTuple {
769 fn extension_id(&self) -> ExtensionId {
770 PRELUDE_ID.clone()
771 }
772
773 fn extension_ref(&self) -> Weak<Extension> {
774 Arc::downgrade(&PRELUDE)
775 }
776}
777
778pub const NOOP_OP_ID: OpName = OpName::new_inline("Noop");
780
781#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
782pub struct NoopDef;
784
785impl std::str::FromStr for NoopDef {
786 type Err = ();
787
788 fn from_str(s: &str) -> Result<Self, Self::Err> {
789 if s == NoopDef.op_id() {
790 Ok(Self)
791 } else {
792 Err(())
793 }
794 }
795}
796
797impl MakeOpDef for NoopDef {
798 fn opdef_id(&self) -> OpName {
799 NOOP_OP_ID
800 }
801
802 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
803 let tv = Type::new_var_use(0, TypeBound::Linear);
804 PolyFuncType::new([TypeBound::Linear.into()], Signature::new_endo(tv)).into()
805 }
806
807 fn description(&self) -> String {
808 "Noop gate".to_string()
809 }
810
811 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
812 try_from_name(op_def.name(), op_def.extension_id())
813 }
814
815 fn extension(&self) -> ExtensionId {
816 PRELUDE_ID.clone()
817 }
818
819 fn extension_ref(&self) -> Weak<Extension> {
820 Arc::downgrade(&PRELUDE)
821 }
822
823 fn post_opdef(&self, def: &mut OpDef) {
824 def.set_constant_folder(*self);
825 }
826}
827
828impl ConstFold for NoopDef {
829 fn fold(
830 &self,
831 _type_args: &[TypeArg],
832 consts: &[(crate::IncomingPort, Value)],
833 ) -> crate::extension::ConstFoldResult {
834 fold_out_row([consts.first()?.1.clone()])
835 }
836}
837
838#[derive(Debug, Clone, PartialEq, Eq)]
840#[non_exhaustive]
841#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
842pub struct Noop(pub Type);
843
844impl Noop {
845 #[must_use]
847 pub fn new(ty: Type) -> Self {
848 Self(ty)
849 }
850}
851
852impl Default for Noop {
853 fn default() -> Self {
854 Self(Type::UNIT)
855 }
856}
857
858impl MakeExtensionOp for Noop {
859 fn op_id(&self) -> OpName {
860 NoopDef.op_id()
861 }
862
863 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
864 where
865 Self: Sized,
866 {
867 let _def = NoopDef::from_def(ext_op.def())?;
868 let [TypeArg::Runtime(ty)] = ext_op.args() else {
869 return Err(SignatureError::InvalidTypeArgs)?;
870 };
871 Ok(Self(ty.clone()))
872 }
873
874 fn type_args(&self) -> Vec<TypeArg> {
875 vec![self.0.clone().into()]
876 }
877}
878
879impl MakeRegisteredOp for Noop {
880 fn extension_id(&self) -> ExtensionId {
881 PRELUDE_ID.clone()
882 }
883
884 fn extension_ref(&self) -> Weak<Extension> {
885 Arc::downgrade(&PRELUDE)
886 }
887}
888
889#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
890pub struct BarrierDef;
892
893pub const BARRIER_OP_ID: OpName = OpName::new_inline("Barrier");
895
896impl std::str::FromStr for BarrierDef {
897 type Err = ();
898
899 fn from_str(s: &str) -> Result<Self, Self::Err> {
900 if s == BarrierDef.op_id() {
901 Ok(Self)
902 } else {
903 Err(())
904 }
905 }
906}
907
908impl MakeOpDef for BarrierDef {
909 fn opdef_id(&self) -> OpName {
910 BARRIER_OP_ID
911 }
912
913 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
914 PolyFuncTypeRV::new(
915 vec![TypeParam::new_list_type(TypeBound::Linear)],
916 FuncValueType::new_endo(TypeRV::new_row_var_use(0, TypeBound::Linear)),
917 )
918 .into()
919 }
920
921 fn description(&self) -> String {
922 "Add a barrier to a row of values".to_string()
923 }
924
925 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
926 try_from_name(op_def.name(), op_def.extension_id())
927 }
928
929 fn extension(&self) -> ExtensionId {
930 PRELUDE_ID.clone()
931 }
932
933 fn extension_ref(&self) -> Weak<Extension> {
934 Arc::downgrade(&PRELUDE)
935 }
936}
937
938#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
941#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
942#[non_exhaustive]
943pub struct Barrier {
944 pub type_row: TypeRow,
946}
947
948impl Barrier {
949 pub fn new(type_row: impl Into<TypeRow>) -> Self {
951 Self {
952 type_row: type_row.into(),
953 }
954 }
955}
956
957impl NamedOp for Barrier {
958 fn name(&self) -> OpName {
959 BarrierDef.op_id()
960 }
961}
962
963impl MakeExtensionOp for Barrier {
964 fn op_id(&self) -> OpName {
965 BarrierDef.op_id()
966 }
967
968 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
969 where
970 Self: Sized,
971 {
972 let _def = BarrierDef::from_def(ext_op.def())?;
973
974 let [TypeArg::List(elems)] = ext_op.args() else {
975 return Err(SignatureError::InvalidTypeArgs)?;
976 };
977 let tys: Result<Vec<Type>, _> = elems
978 .iter()
979 .map(|a| match a {
980 TypeArg::Runtime(ty) => Ok(ty.clone()),
981 _ => Err(SignatureError::InvalidTypeArgs),
982 })
983 .collect();
984 Ok(Self {
985 type_row: tys?.into(),
986 })
987 }
988
989 fn type_args(&self) -> Vec<TypeArg> {
990 vec![TypeArg::new_list(
991 self.type_row.iter().map(|t| t.clone().into()),
992 )]
993 }
994}
995
996impl MakeRegisteredOp for Barrier {
997 fn extension_id(&self) -> ExtensionId {
998 PRELUDE_ID.clone()
999 }
1000
1001 fn extension_ref(&self) -> Weak<Extension> {
1002 Arc::downgrade(&PRELUDE)
1003 }
1004}
1005
1006#[cfg(test)]
1007mod test {
1008 use crate::builder::inout_sig;
1009 use crate::std_extensions::arithmetic::float_types::{ConstF64, float64_type};
1010 use crate::types::Term;
1011 use crate::{
1012 Hugr, Wire,
1013 builder::{DFGBuilder, Dataflow, DataflowHugr, endo_sig},
1014 utils::test_quantum_extension::cx_gate,
1015 };
1016
1017 use super::*;
1018 use crate::{
1019 ops::{OpTrait, OpType},
1020 type_row,
1021 };
1022
1023 use crate::hugr::views::HugrView;
1024
1025 #[test]
1026 fn test_make_tuple() {
1027 let op = MakeTuple::new(type_row![Type::UNIT]);
1028 let optype: OpType = op.clone().into();
1029 assert_eq!(
1030 optype.dataflow_signature().unwrap().io(),
1031 (
1032 &type_row![Type::UNIT],
1033 &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
1034 )
1035 );
1036
1037 let new_op = MakeTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1038 assert_eq!(new_op, op);
1039 }
1040
1041 #[test]
1042 fn test_unmake_tuple() {
1043 let op = UnpackTuple::new(type_row![Type::UNIT]);
1044 let optype: OpType = op.clone().into();
1045 assert_eq!(
1046 optype.dataflow_signature().unwrap().io(),
1047 (
1048 &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
1049 &type_row![Type::UNIT],
1050 )
1051 );
1052
1053 let new_op = UnpackTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1054 assert_eq!(new_op, op);
1055 }
1056
1057 #[test]
1058 fn test_noop() {
1059 let op = Noop::new(Type::UNIT);
1060 let optype: OpType = op.clone().into();
1061 assert_eq!(
1062 optype.dataflow_signature().unwrap().io(),
1063 (&type_row![Type::UNIT], &type_row![Type::UNIT])
1064 );
1065
1066 let new_op = Noop::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1067 assert_eq!(new_op, op);
1068 }
1069
1070 #[test]
1071 fn test_lift() {
1072 let op = Barrier::new(type_row![Type::UNIT]);
1073 let optype: OpType = op.clone().into();
1074 assert_eq!(
1075 optype.dataflow_signature().unwrap().as_ref(),
1076 &Signature::new_endo(type_row![Type::UNIT])
1077 );
1078
1079 let new_op = Barrier::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1080 assert_eq!(new_op, op);
1081 }
1082
1083 #[test]
1084 fn test_option() {
1085 let typ: Type = option_type(bool_t()).into();
1086 let const_val1 = const_some(Value::true_val());
1087 let const_val2 = const_none(bool_t());
1088
1089 let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1090
1091 let some = b.add_load_value(const_val1);
1092 let none = b.add_load_value(const_val2);
1093
1094 b.finish_hugr_with_outputs([some, none]).unwrap();
1095 }
1096
1097 #[test]
1098 fn test_result() {
1099 let typ: Type = either_type(bool_t(), float64_type()).into();
1100 let const_bool = const_left(Value::true_val(), float64_type());
1101 let const_float = const_right(bool_t(), ConstF64::new(0.5).into());
1102
1103 let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1104
1105 let bool = b.add_load_value(const_bool);
1106 let float = b.add_load_value(const_float);
1107
1108 b.finish_hugr_with_outputs([bool, float]).unwrap();
1109 }
1110
1111 #[test]
1112 fn test_error_type() {
1114 let ext_def = PRELUDE
1115 .get_type(&ERROR_TYPE_NAME)
1116 .unwrap()
1117 .instantiate([])
1118 .unwrap();
1119
1120 let ext_type = Type::new_extension(ext_def);
1121 assert_eq!(ext_type, error_type());
1122
1123 let error_val = ConstError::new(2, "my message");
1124
1125 assert_eq!(error_val.name(), "ConstError(2, \"my message\")");
1126
1127 assert!(error_val.validate().is_ok());
1128
1129 assert!(error_val.equal_consts(&ConstError::new(2, "my message")));
1130 assert!(!error_val.equal_consts(&ConstError::new(3, "my message")));
1131
1132 let mut b = DFGBuilder::new(endo_sig(type_row![])).unwrap();
1133
1134 let err = b.add_load_value(error_val);
1135
1136 let op = PRELUDE
1137 .instantiate_extension_op(&EXIT_OP_ID, [Term::new_list([]), Term::new_list([])])
1138 .unwrap();
1139
1140 b.add_dataflow_op(op, [err]).unwrap();
1141
1142 b.finish_hugr_with_outputs([]).unwrap();
1143 }
1144
1145 #[test]
1146 fn test_make_error() {
1148 let err_op = PRELUDE
1149 .instantiate_extension_op(&MAKE_ERROR_OP_ID, [])
1150 .unwrap();
1151 let panic_op = PRELUDE
1152 .instantiate_extension_op(&EXIT_OP_ID, [Term::new_list([]), Term::new_list([])])
1153 .unwrap();
1154
1155 let mut b =
1156 DFGBuilder::new(Signature::new(vec![usize_t(), string_type()], type_row![])).unwrap();
1157 let [signal, message] = b.input_wires_arr();
1158 let err_value = b.add_dataflow_op(err_op, [signal, message]).unwrap();
1159 b.add_dataflow_op(panic_op, err_value.outputs()).unwrap();
1160
1161 let h = b.finish_hugr_with_outputs([]).unwrap();
1162 h.validate().unwrap();
1163 }
1164
1165 #[test]
1166 fn test_panic_with_io() {
1168 let error_val = ConstError::new(42, "PANIC");
1169 let type_arg_q: Term = qb_t().into();
1170 let type_arg_2q: Term = Term::new_list([type_arg_q.clone(), type_arg_q]);
1171 let panic_op = PRELUDE
1172 .instantiate_extension_op(&PANIC_OP_ID, [type_arg_2q.clone(), type_arg_2q.clone()])
1173 .unwrap();
1174
1175 let mut b = DFGBuilder::new(endo_sig(vec![qb_t(), qb_t()])).unwrap();
1176 let [q0, q1] = b.input_wires_arr();
1177 let [q0, q1] = b
1178 .add_dataflow_op(cx_gate(), [q0, q1])
1179 .unwrap()
1180 .outputs_arr();
1181 let err = b.add_load_value(error_val);
1182 let [q0, q1] = b
1183 .add_dataflow_op(panic_op, [err, q0, q1])
1184 .unwrap()
1185 .outputs_arr();
1186 b.finish_hugr_with_outputs([q0, q1]).unwrap();
1187 }
1188
1189 #[test]
1190 fn test_string_type() {
1192 let string_custom_type: CustomType = PRELUDE
1193 .get_type(&STRING_TYPE_NAME)
1194 .unwrap()
1195 .instantiate([])
1196 .unwrap();
1197 let string_ty: Type = Type::new_extension(string_custom_type);
1198 assert_eq!(string_ty, string_type());
1199 let string_const: ConstString = ConstString::new("Lorem ipsum".into());
1200 assert_eq!(string_const.name(), "ConstString(\"Lorem ipsum\")");
1201 assert!(string_const.validate().is_ok());
1202 assert!(string_const.equal_consts(&ConstString::new("Lorem ipsum".into())));
1203 assert!(!string_const.equal_consts(&ConstString::new("Lorem ispum".into())));
1204 }
1205
1206 #[test]
1207 fn test_print() {
1209 let mut b: DFGBuilder<Hugr> = DFGBuilder::new(endo_sig(vec![])).unwrap();
1210 let greeting: ConstString = ConstString::new("Hello, world!".into());
1211 let greeting_out: Wire = b.add_load_value(greeting);
1212 let print_op = PRELUDE.instantiate_extension_op(&PRINT_OP_ID, []).unwrap();
1213 b.add_dataflow_op(print_op, [greeting_out]).unwrap();
1214 b.finish_hugr_with_outputs([]).unwrap();
1215 }
1216
1217 #[test]
1218 fn test_external_symbol() {
1219 let subject = ConstExternalSymbol::new("foo", Type::UNIT, false);
1220 assert_eq!(subject.get_type(), Type::UNIT);
1221 assert_eq!(subject.name(), "@foo");
1222 assert!(subject.validate().is_ok());
1223 assert!(subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, false)));
1224 assert!(!subject.equal_consts(&ConstExternalSymbol::new("bar", Type::UNIT, false)));
1225 assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", string_type(), false)));
1226 assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, true)));
1227
1228 assert!(
1229 ConstExternalSymbol::new("", Type::UNIT, true)
1230 .validate()
1231 .is_err()
1232 );
1233 }
1234}