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, ExtensionSet, 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 extension_reqs(&self) -> ExtensionSet {
249 ExtensionSet::singleton(PRELUDE_ID)
250 }
251
252 fn get_type(&self) -> Type {
253 string_type()
254 }
255}
256
257pub const PRINT_OP_ID: OpName = OpName::new_inline("print");
259
260fn error_custom_type(extension_ref: &Weak<Extension>) -> CustomType {
265 CustomType::new(
266 ERROR_TYPE_NAME,
267 vec![],
268 PRELUDE_ID,
269 TypeBound::Copyable,
270 extension_ref,
271 )
272}
273
274pub fn error_type() -> Type {
276 error_custom_type(&Arc::downgrade(&PRELUDE)).into()
277}
278
279pub const ERROR_TYPE_NAME: TypeName = TypeName::new_inline("error");
281
282pub fn sum_with_error(ty: impl Into<TypeRowRV>) -> SumType {
284 either_type(error_type(), ty)
285}
286
287#[inline]
289pub fn option_type(ty: impl Into<TypeRowRV>) -> SumType {
290 either_type(TypeRow::new(), ty)
291}
292
293#[inline]
298pub fn either_type(ty_left: impl Into<TypeRowRV>, ty_right: impl Into<TypeRowRV>) -> SumType {
299 SumType::new([ty_left.into(), ty_right.into()])
300}
301
302pub fn const_some(value: Value) -> Value {
306 const_some_tuple([value])
307}
308
309pub fn const_some_tuple(values: impl IntoIterator<Item = Value>) -> Value {
315 const_right_tuple(TypeRow::new(), values)
316}
317
318pub fn const_none(ty: impl Into<TypeRowRV>) -> Value {
322 const_left_tuple([], ty)
323}
324
325pub fn const_left(value: Value, ty_right: impl Into<TypeRowRV>) -> Value {
331 const_left_tuple([value], ty_right)
332}
333
334pub fn const_left_tuple(
340 values: impl IntoIterator<Item = Value>,
341 ty_right: impl Into<TypeRowRV>,
342) -> Value {
343 let values = values.into_iter().collect_vec();
344 let types: TypeRowRV = values
345 .iter()
346 .map(|v| TypeRV::from(v.get_type()))
347 .collect_vec()
348 .into();
349 let typ = either_type(types, ty_right);
350 Value::sum(0, values, typ).unwrap()
351}
352
353pub fn const_right(ty_left: impl Into<TypeRowRV>, value: Value) -> Value {
359 const_right_tuple(ty_left, [value])
360}
361
362pub fn const_right_tuple(
368 ty_left: impl Into<TypeRowRV>,
369 values: impl IntoIterator<Item = Value>,
370) -> Value {
371 let values = values.into_iter().collect_vec();
372 let types: TypeRowRV = values
373 .iter()
374 .map(|v| TypeRV::from(v.get_type()))
375 .collect_vec()
376 .into();
377 let typ = either_type(ty_left, types);
378 Value::sum(1, values, typ).unwrap()
379}
380
381pub fn const_ok(value: Value, ty_fail: impl Into<TypeRowRV>) -> Value {
385 const_right(ty_fail, value)
386}
387
388pub fn const_ok_tuple(
392 values: impl IntoIterator<Item = Value>,
393 ty_fail: impl Into<TypeRowRV>,
394) -> Value {
395 const_right_tuple(ty_fail, values)
396}
397
398pub fn const_fail(value: Value, ty_ok: impl Into<TypeRowRV>) -> Value {
402 const_left(value, ty_ok)
403}
404
405pub fn const_fail_tuple(
409 values: impl IntoIterator<Item = Value>,
410 ty_ok: impl Into<TypeRowRV>,
411) -> Value {
412 const_left_tuple(values, ty_ok)
413}
414
415#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
416pub struct ConstUsize(u64);
418
419impl ConstUsize {
420 pub fn new(value: u64) -> Self {
422 Self(value)
423 }
424
425 pub fn value(&self) -> u64 {
427 self.0
428 }
429}
430
431#[typetag::serde]
432impl CustomConst for ConstUsize {
433 fn name(&self) -> ValueName {
434 format!("ConstUsize({})", self.0).into()
435 }
436
437 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
438 crate::ops::constant::downcast_equal_consts(self, other)
439 }
440
441 fn extension_reqs(&self) -> ExtensionSet {
442 ExtensionSet::singleton(PRELUDE_ID)
443 }
444
445 fn get_type(&self) -> Type {
446 usize_t()
447 }
448}
449
450#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
451pub struct ConstError {
455 pub signal: u32,
457 pub message: String,
459}
460
461pub const DEFAULT_ERROR_SIGNAL: u32 = 1;
463
464impl ConstError {
465 pub fn new(signal: u32, message: impl ToString) -> Self {
467 Self {
468 signal,
469 message: message.to_string(),
470 }
471 }
472
473 pub fn new_default_signal(message: impl ToString) -> Self {
477 Self::new(DEFAULT_ERROR_SIGNAL, message)
478 }
479 pub fn as_either(self, ty_ok: impl Into<TypeRowRV>) -> Value {
484 const_fail(self.into(), ty_ok)
485 }
486}
487
488#[typetag::serde]
489impl CustomConst for ConstError {
490 fn name(&self) -> ValueName {
491 format!("ConstError({}, {:?})", self.signal, self.message).into()
492 }
493
494 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
495 crate::ops::constant::downcast_equal_consts(self, other)
496 }
497
498 fn extension_reqs(&self) -> ExtensionSet {
499 ExtensionSet::singleton(PRELUDE_ID)
500 }
501 fn get_type(&self) -> Type {
502 error_type()
503 }
504}
505
506impl FromStr for ConstError {
507 type Err = ();
508
509 fn from_str(s: &str) -> Result<Self, Self::Err> {
510 Ok(Self::new_default_signal(s))
511 }
512}
513
514impl From<String> for ConstError {
515 fn from(s: String) -> Self {
516 Self::new_default_signal(s)
517 }
518}
519
520#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
521pub struct ConstExternalSymbol {
523 pub symbol: String,
525 pub typ: Type,
527 pub constant: bool,
529}
530
531impl ConstExternalSymbol {
532 pub fn new(symbol: impl Into<String>, typ: impl Into<Type>, constant: bool) -> Self {
534 Self {
535 symbol: symbol.into(),
536 typ: typ.into(),
537 constant,
538 }
539 }
540}
541
542impl PartialEq<dyn CustomConst> for ConstExternalSymbol {
543 fn eq(&self, other: &dyn CustomConst) -> bool {
544 self.equal_consts(other)
545 }
546}
547
548#[typetag::serde]
549impl CustomConst for ConstExternalSymbol {
550 fn name(&self) -> ValueName {
551 format!("@{}", &self.symbol).into()
552 }
553
554 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
555 crate::ops::constant::downcast_equal_consts(self, other)
556 }
557
558 fn extension_reqs(&self) -> ExtensionSet {
559 ExtensionSet::singleton(PRELUDE_ID)
560 }
561 fn get_type(&self) -> Type {
562 self.typ.clone()
563 }
564
565 fn update_extensions(
566 &mut self,
567 extensions: &WeakExtensionRegistry,
568 ) -> Result<(), ExtensionResolutionError> {
569 resolve_type_extensions(&mut self.typ, extensions)
570 }
571
572 fn validate(&self) -> Result<(), CustomCheckFailure> {
573 if self.symbol.is_empty() {
574 Err(CustomCheckFailure::Message(
575 "External symbol name is empty.".into(),
576 ))
577 } else {
578 Ok(())
579 }
580 }
581}
582
583#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, EnumIter, IntoStaticStr, EnumString)]
585#[allow(missing_docs)]
586#[non_exhaustive]
587pub enum TupleOpDef {
588 MakeTuple,
589 UnpackTuple,
590}
591
592impl ConstFold for TupleOpDef {
593 fn fold(
594 &self,
595 _type_args: &[TypeArg],
596 consts: &[(crate::IncomingPort, Value)],
597 ) -> crate::extension::ConstFoldResult {
598 match self {
599 TupleOpDef::MakeTuple => {
600 fold_out_row([Value::tuple(sorted_consts(consts).into_iter().cloned())])
601 }
602 TupleOpDef::UnpackTuple => {
603 let c = &consts.first()?.1;
604 let Some(vs) = c.as_tuple() else {
605 panic!("This op always takes a Tuple input.");
606 };
607 fold_out_row(vs.iter().cloned())
608 }
609 }
610 }
611}
612impl MakeOpDef for TupleOpDef {
613 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
614 let rv = TypeRV::new_row_var_use(0, TypeBound::Any);
615 let tuple_type = TypeRV::new_tuple(vec![rv.clone()]);
616
617 let param = TypeParam::new_list(TypeBound::Any);
618 match self {
619 TupleOpDef::MakeTuple => {
620 PolyFuncTypeRV::new([param], FuncValueType::new(rv, tuple_type))
621 }
622 TupleOpDef::UnpackTuple => {
623 PolyFuncTypeRV::new([param], FuncValueType::new(tuple_type, rv))
624 }
625 }
626 .into()
627 }
628
629 fn description(&self) -> String {
630 match self {
631 TupleOpDef::MakeTuple => "MakeTuple operation",
632 TupleOpDef::UnpackTuple => "UnpackTuple operation",
633 }
634 .to_string()
635 }
636
637 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
638 try_from_name(op_def.name(), op_def.extension_id())
639 }
640
641 fn extension(&self) -> ExtensionId {
642 PRELUDE_ID.to_owned()
643 }
644
645 fn extension_ref(&self) -> Weak<Extension> {
646 Arc::downgrade(&PRELUDE)
647 }
648
649 fn post_opdef(&self, def: &mut OpDef) {
650 def.set_constant_folder(*self);
651 }
652}
653#[derive(Debug, Clone, Default, PartialEq, Eq)]
655#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
656#[non_exhaustive]
657pub struct MakeTuple(pub TypeRow);
658
659impl MakeTuple {
660 pub fn new(tys: TypeRow) -> Self {
662 Self(tys)
663 }
664}
665
666impl NamedOp for MakeTuple {
667 fn name(&self) -> OpName {
668 TupleOpDef::MakeTuple.name()
669 }
670}
671
672impl MakeExtensionOp for MakeTuple {
673 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
674 where
675 Self: Sized,
676 {
677 let def = TupleOpDef::from_def(ext_op.def())?;
678 if def != TupleOpDef::MakeTuple {
679 return Err(OpLoadError::NotMember(ext_op.def().name().to_string()))?;
680 }
681 let [TypeArg::Sequence { elems }] = ext_op.args() else {
682 return Err(SignatureError::InvalidTypeArgs)?;
683 };
684 let tys: Result<Vec<Type>, _> = elems
685 .iter()
686 .map(|a| match a {
687 TypeArg::Type { ty } => Ok(ty.clone()),
688 _ => Err(SignatureError::InvalidTypeArgs),
689 })
690 .collect();
691 Ok(Self(tys?.into()))
692 }
693
694 fn type_args(&self) -> Vec<TypeArg> {
695 vec![TypeArg::Sequence {
696 elems: self
697 .0
698 .iter()
699 .map(|t| TypeArg::Type { ty: t.clone() })
700 .collect(),
701 }]
702 }
703}
704
705impl MakeRegisteredOp for MakeTuple {
706 fn extension_id(&self) -> ExtensionId {
707 PRELUDE_ID.to_owned()
708 }
709
710 fn extension_ref(&self) -> Weak<Extension> {
711 Arc::downgrade(&PRELUDE)
712 }
713}
714
715#[derive(Debug, Clone, Default, PartialEq, Eq)]
717#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
718#[non_exhaustive]
719pub struct UnpackTuple(pub TypeRow);
720
721impl UnpackTuple {
722 pub fn new(tys: TypeRow) -> Self {
724 Self(tys)
725 }
726}
727
728impl NamedOp for UnpackTuple {
729 fn name(&self) -> OpName {
730 TupleOpDef::UnpackTuple.name()
731 }
732}
733
734impl MakeExtensionOp for UnpackTuple {
735 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
736 where
737 Self: Sized,
738 {
739 let def = TupleOpDef::from_def(ext_op.def())?;
740 if def != TupleOpDef::UnpackTuple {
741 return Err(OpLoadError::NotMember(ext_op.def().name().to_string()))?;
742 }
743 let [TypeArg::Sequence { elems }] = ext_op.args() else {
744 return Err(SignatureError::InvalidTypeArgs)?;
745 };
746 let tys: Result<Vec<Type>, _> = elems
747 .iter()
748 .map(|a| match a {
749 TypeArg::Type { ty } => Ok(ty.clone()),
750 _ => Err(SignatureError::InvalidTypeArgs),
751 })
752 .collect();
753 Ok(Self(tys?.into()))
754 }
755
756 fn type_args(&self) -> Vec<TypeArg> {
757 vec![TypeArg::Sequence {
758 elems: self
759 .0
760 .iter()
761 .map(|t| TypeArg::Type { ty: t.clone() })
762 .collect(),
763 }]
764 }
765}
766
767impl MakeRegisteredOp for UnpackTuple {
768 fn extension_id(&self) -> ExtensionId {
769 PRELUDE_ID.to_owned()
770 }
771
772 fn extension_ref(&self) -> Weak<Extension> {
773 Arc::downgrade(&PRELUDE)
774 }
775}
776
777#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
778pub struct NoopDef;
780
781impl NamedOp for NoopDef {
782 fn name(&self) -> OpName {
783 "Noop".into()
784 }
785}
786
787impl std::str::FromStr for NoopDef {
788 type Err = ();
789
790 fn from_str(s: &str) -> Result<Self, Self::Err> {
791 if s == NoopDef.name() {
792 Ok(Self)
793 } else {
794 Err(())
795 }
796 }
797}
798impl MakeOpDef for NoopDef {
799 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
800 let tv = Type::new_var_use(0, TypeBound::Any);
801 PolyFuncType::new([TypeBound::Any.into()], Signature::new_endo(tv)).into()
802 }
803
804 fn description(&self) -> String {
805 "Noop gate".to_string()
806 }
807
808 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
809 try_from_name(op_def.name(), op_def.extension_id())
810 }
811
812 fn extension(&self) -> ExtensionId {
813 PRELUDE_ID.to_owned()
814 }
815
816 fn extension_ref(&self) -> Weak<Extension> {
817 Arc::downgrade(&PRELUDE)
818 }
819
820 fn post_opdef(&self, def: &mut OpDef) {
821 def.set_constant_folder(*self);
822 }
823}
824
825impl ConstFold for NoopDef {
826 fn fold(
827 &self,
828 _type_args: &[TypeArg],
829 consts: &[(crate::IncomingPort, Value)],
830 ) -> crate::extension::ConstFoldResult {
831 fold_out_row([consts.first()?.1.clone()])
832 }
833}
834
835#[derive(Debug, Clone, PartialEq, Eq)]
837#[non_exhaustive]
838#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
839pub struct Noop(pub Type);
840
841impl Noop {
842 pub fn new(ty: Type) -> Self {
844 Self(ty)
845 }
846}
847
848impl Default for Noop {
849 fn default() -> Self {
850 Self(Type::UNIT)
851 }
852}
853impl NamedOp for Noop {
854 fn name(&self) -> OpName {
855 NoopDef.name()
856 }
857}
858
859impl MakeExtensionOp for Noop {
860 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
861 where
862 Self: Sized,
863 {
864 let _def = NoopDef::from_def(ext_op.def())?;
865 let [TypeArg::Type { ty }] = ext_op.args() else {
866 return Err(SignatureError::InvalidTypeArgs)?;
867 };
868 Ok(Self(ty.clone()))
869 }
870
871 fn type_args(&self) -> Vec<TypeArg> {
872 vec![TypeArg::Type { ty: self.0.clone() }]
873 }
874}
875
876impl MakeRegisteredOp for Noop {
877 fn extension_id(&self) -> ExtensionId {
878 PRELUDE_ID.to_owned()
879 }
880
881 fn extension_ref(&self) -> Weak<Extension> {
882 Arc::downgrade(&PRELUDE)
883 }
884}
885
886#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
887pub struct BarrierDef;
889
890pub const BARRIER_OP_ID: OpName = OpName::new_inline("Barrier");
892impl NamedOp for BarrierDef {
893 fn name(&self) -> OpName {
894 BARRIER_OP_ID
895 }
896}
897
898impl std::str::FromStr for BarrierDef {
899 type Err = ();
900
901 fn from_str(s: &str) -> Result<Self, Self::Err> {
902 if s == BarrierDef.name() {
903 Ok(Self)
904 } else {
905 Err(())
906 }
907 }
908}
909
910impl MakeOpDef for BarrierDef {
911 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
912 PolyFuncTypeRV::new(
913 vec![TypeParam::new_list(TypeBound::Any)],
914 FuncValueType::new_endo(TypeRV::new_row_var_use(0, TypeBound::Any)),
915 )
916 .into()
917 }
918
919 fn description(&self) -> String {
920 "Add a barrier to a row of values".to_string()
921 }
922
923 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
924 try_from_name(op_def.name(), op_def.extension_id())
925 }
926
927 fn extension(&self) -> ExtensionId {
928 PRELUDE_ID.to_owned()
929 }
930
931 fn extension_ref(&self) -> Weak<Extension> {
932 Arc::downgrade(&PRELUDE)
933 }
934}
935
936#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
939#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
940#[non_exhaustive]
941pub struct Barrier {
942 pub type_row: TypeRow,
944}
945
946impl Barrier {
947 pub fn new(type_row: impl Into<TypeRow>) -> Self {
949 Self {
950 type_row: type_row.into(),
951 }
952 }
953}
954
955impl NamedOp for Barrier {
956 fn name(&self) -> OpName {
957 BarrierDef.name()
958 }
959}
960
961impl MakeExtensionOp for Barrier {
962 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
963 where
964 Self: Sized,
965 {
966 let _def = BarrierDef::from_def(ext_op.def())?;
967
968 let [TypeArg::Sequence { elems }] = ext_op.args() else {
969 return Err(SignatureError::InvalidTypeArgs)?;
970 };
971 let tys: Result<Vec<Type>, _> = elems
972 .iter()
973 .map(|a| match a {
974 TypeArg::Type { ty } => Ok(ty.clone()),
975 _ => Err(SignatureError::InvalidTypeArgs),
976 })
977 .collect();
978 Ok(Self {
979 type_row: tys?.into(),
980 })
981 }
982
983 fn type_args(&self) -> Vec<TypeArg> {
984 vec![TypeArg::Sequence {
985 elems: self
986 .type_row
987 .iter()
988 .map(|t| TypeArg::Type { ty: t.clone() })
989 .collect(),
990 }]
991 }
992}
993
994impl MakeRegisteredOp for Barrier {
995 fn extension_id(&self) -> ExtensionId {
996 PRELUDE_ID.to_owned()
997 }
998
999 fn extension_ref(&self) -> Weak<Extension> {
1000 Arc::downgrade(&PRELUDE)
1001 }
1002}
1003
1004#[cfg(test)]
1005mod test {
1006 use crate::builder::inout_sig;
1007 use crate::std_extensions::arithmetic::float_types::{float64_type, ConstF64};
1008 use crate::{
1009 builder::{endo_sig, DFGBuilder, Dataflow, DataflowHugr},
1010 utils::test_quantum_extension::cx_gate,
1011 Hugr, Wire,
1012 };
1013
1014 use super::*;
1015 use crate::{
1016 ops::{OpTrait, OpType},
1017 type_row,
1018 };
1019
1020 #[test]
1021 fn test_make_tuple() {
1022 let op = MakeTuple::new(type_row![Type::UNIT]);
1023 let optype: OpType = op.clone().into();
1024 assert_eq!(
1025 optype.dataflow_signature().unwrap().io(),
1026 (
1027 &type_row![Type::UNIT],
1028 &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
1029 )
1030 );
1031
1032 let new_op = MakeTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1033 assert_eq!(new_op, op);
1034 }
1035
1036 #[test]
1037 fn test_unmake_tuple() {
1038 let op = UnpackTuple::new(type_row![Type::UNIT]);
1039 let optype: OpType = op.clone().into();
1040 assert_eq!(
1041 optype.dataflow_signature().unwrap().io(),
1042 (
1043 &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
1044 &type_row![Type::UNIT],
1045 )
1046 );
1047
1048 let new_op = UnpackTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1049 assert_eq!(new_op, op);
1050 }
1051
1052 #[test]
1053 fn test_noop() {
1054 let op = Noop::new(Type::UNIT);
1055 let optype: OpType = op.clone().into();
1056 assert_eq!(
1057 optype.dataflow_signature().unwrap().io(),
1058 (&type_row![Type::UNIT], &type_row![Type::UNIT])
1059 );
1060
1061 let new_op = Noop::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1062 assert_eq!(new_op, op);
1063 }
1064
1065 #[test]
1066 fn test_lift() {
1067 let op = Barrier::new(type_row![Type::UNIT]);
1068 let optype: OpType = op.clone().into();
1069 assert_eq!(
1070 optype.dataflow_signature().unwrap().as_ref(),
1071 &Signature::new_endo(type_row![Type::UNIT]).with_prelude()
1072 );
1073
1074 let new_op = Barrier::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1075 assert_eq!(new_op, op);
1076 }
1077
1078 #[test]
1079 fn test_option() {
1080 let typ: Type = option_type(bool_t()).into();
1081 let const_val1 = const_some(Value::true_val());
1082 let const_val2 = const_none(bool_t());
1083
1084 let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1085
1086 let some = b.add_load_value(const_val1);
1087 let none = b.add_load_value(const_val2);
1088
1089 b.finish_hugr_with_outputs([some, none]).unwrap();
1090 }
1091
1092 #[test]
1093 fn test_result() {
1094 let typ: Type = either_type(bool_t(), float64_type()).into();
1095 let const_bool = const_left(Value::true_val(), float64_type());
1096 let const_float = const_right(bool_t(), ConstF64::new(0.5).into());
1097
1098 let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1099
1100 let bool = b.add_load_value(const_bool);
1101 let float = b.add_load_value(const_float);
1102
1103 b.finish_hugr_with_outputs([bool, float]).unwrap();
1104 }
1105
1106 #[test]
1107 fn test_error_type() {
1109 let ext_def = PRELUDE
1110 .get_type(&ERROR_TYPE_NAME)
1111 .unwrap()
1112 .instantiate([])
1113 .unwrap();
1114
1115 let ext_type = Type::new_extension(ext_def);
1116 assert_eq!(ext_type, error_type());
1117
1118 let error_val = ConstError::new(2, "my message");
1119
1120 assert_eq!(error_val.name(), "ConstError(2, \"my message\")");
1121
1122 assert!(error_val.validate().is_ok());
1123
1124 assert_eq!(
1125 error_val.extension_reqs(),
1126 ExtensionSet::singleton(PRELUDE_ID)
1127 );
1128 assert!(error_val.equal_consts(&ConstError::new(2, "my message")));
1129 assert!(!error_val.equal_consts(&ConstError::new(3, "my message")));
1130
1131 let mut b = DFGBuilder::new(endo_sig(type_row![])).unwrap();
1132
1133 let err = b.add_load_value(error_val);
1134
1135 const TYPE_ARG_NONE: TypeArg = TypeArg::Sequence { elems: vec![] };
1136 let op = PRELUDE
1137 .instantiate_extension_op(&EXIT_OP_ID, [TYPE_ARG_NONE, TYPE_ARG_NONE])
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_panic_with_io() {
1148 let error_val = ConstError::new(42, "PANIC");
1149 let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() };
1150 let type_arg_2q: TypeArg = TypeArg::Sequence {
1151 elems: vec![type_arg_q.clone(), type_arg_q],
1152 };
1153 let panic_op = PRELUDE
1154 .instantiate_extension_op(&PANIC_OP_ID, [type_arg_2q.clone(), type_arg_2q.clone()])
1155 .unwrap();
1156
1157 let mut b = DFGBuilder::new(endo_sig(vec![qb_t(), qb_t()])).unwrap();
1158 let [q0, q1] = b.input_wires_arr();
1159 let [q0, q1] = b
1160 .add_dataflow_op(cx_gate(), [q0, q1])
1161 .unwrap()
1162 .outputs_arr();
1163 let err = b.add_load_value(error_val);
1164 let [q0, q1] = b
1165 .add_dataflow_op(panic_op, [err, q0, q1])
1166 .unwrap()
1167 .outputs_arr();
1168 b.finish_hugr_with_outputs([q0, q1]).unwrap();
1169 }
1170
1171 #[test]
1172 fn test_string_type() {
1174 let string_custom_type: CustomType = PRELUDE
1175 .get_type(&STRING_TYPE_NAME)
1176 .unwrap()
1177 .instantiate([])
1178 .unwrap();
1179 let string_ty: Type = Type::new_extension(string_custom_type);
1180 assert_eq!(string_ty, string_type());
1181 let string_const: ConstString = ConstString::new("Lorem ipsum".into());
1182 assert_eq!(string_const.name(), "ConstString(\"Lorem ipsum\")");
1183 assert!(string_const.validate().is_ok());
1184 assert_eq!(
1185 string_const.extension_reqs(),
1186 ExtensionSet::singleton(PRELUDE_ID)
1187 );
1188 assert!(string_const.equal_consts(&ConstString::new("Lorem ipsum".into())));
1189 assert!(!string_const.equal_consts(&ConstString::new("Lorem ispum".into())));
1190 }
1191
1192 #[test]
1193 fn test_print() {
1195 let mut b: DFGBuilder<Hugr> = DFGBuilder::new(endo_sig(vec![])).unwrap();
1196 let greeting: ConstString = ConstString::new("Hello, world!".into());
1197 let greeting_out: Wire = b.add_load_value(greeting);
1198 let print_op = PRELUDE.instantiate_extension_op(&PRINT_OP_ID, []).unwrap();
1199 b.add_dataflow_op(print_op, [greeting_out]).unwrap();
1200 b.finish_hugr_with_outputs([]).unwrap();
1201 }
1202
1203 #[test]
1204 fn test_external_symbol() {
1205 let subject = ConstExternalSymbol::new("foo", Type::UNIT, false);
1206 assert_eq!(subject.get_type(), Type::UNIT);
1207 assert_eq!(subject.name(), "@foo");
1208 assert!(subject.validate().is_ok());
1209 assert_eq!(
1210 subject.extension_reqs(),
1211 ExtensionSet::singleton(PRELUDE_ID)
1212 );
1213 assert!(subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, false)));
1214 assert!(!subject.equal_consts(&ConstExternalSymbol::new("bar", Type::UNIT, false)));
1215 assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", string_type(), false)));
1216 assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, true)));
1217
1218 assert!(ConstExternalSymbol::new("", Type::UNIT, true)
1219 .validate()
1220 .is_err())
1221 }
1222}