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