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