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