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, 1, 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), 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
113 TupleOpDef::load_all_ops(prelude, extension_ref).unwrap();
114 NoopDef.add_to_extension(prelude, extension_ref).unwrap();
115 LiftDef.add_to_extension(prelude, extension_ref).unwrap();
116 generic::LoadNatDef.add_to_extension(prelude, extension_ref).unwrap();
117 })
118 };
119
120 pub static ref PRELUDE_REGISTRY: ExtensionRegistry = ExtensionRegistry::new([PRELUDE.clone()]);
122}
123
124pub(crate) fn usize_custom_t(extension_ref: &Weak<Extension>) -> CustomType {
125 CustomType::new(
126 TypeName::new_inline("usize"),
127 vec![],
128 PRELUDE_ID,
129 TypeBound::Copyable,
130 extension_ref,
131 )
132}
133
134pub(crate) fn qb_custom_t(extension_ref: &Weak<Extension>) -> CustomType {
135 CustomType::new(
136 TypeName::new_inline("qubit"),
137 vec![],
138 PRELUDE_ID,
139 TypeBound::Any,
140 extension_ref,
141 )
142}
143
144pub fn qb_t() -> Type {
146 qb_custom_t(&Arc::downgrade(&PRELUDE)).into()
147}
148pub fn usize_t() -> Type {
150 usize_custom_t(&Arc::downgrade(&PRELUDE)).into()
151}
152pub fn bool_t() -> Type {
154 Type::new_unit_sum(2)
155}
156
157pub const PANIC_OP_ID: OpName = OpName::new_inline("panic");
167
168pub const STRING_TYPE_NAME: TypeName = TypeName::new_inline("string");
170
171fn string_custom_type(extension_ref: &Weak<Extension>) -> CustomType {
176 CustomType::new(
177 STRING_TYPE_NAME,
178 vec![],
179 PRELUDE_ID,
180 TypeBound::Copyable,
181 extension_ref,
182 )
183}
184
185pub fn string_type() -> Type {
187 string_custom_type(&Arc::downgrade(&PRELUDE)).into()
188}
189
190#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
191pub struct ConstString(String);
193
194impl ConstString {
195 pub fn new(value: String) -> Self {
197 Self(value)
198 }
199
200 pub fn value(&self) -> &str {
202 &self.0
203 }
204}
205
206#[typetag::serde]
207impl CustomConst for ConstString {
208 fn name(&self) -> ValueName {
209 format!("ConstString({:?})", self.0).into()
210 }
211
212 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
213 crate::ops::constant::downcast_equal_consts(self, other)
214 }
215
216 fn extension_reqs(&self) -> ExtensionSet {
217 ExtensionSet::singleton(PRELUDE_ID)
218 }
219
220 fn get_type(&self) -> Type {
221 string_type()
222 }
223}
224
225pub const PRINT_OP_ID: OpName = OpName::new_inline("print");
227
228fn error_custom_type(extension_ref: &Weak<Extension>) -> CustomType {
233 CustomType::new(
234 ERROR_TYPE_NAME,
235 vec![],
236 PRELUDE_ID,
237 TypeBound::Copyable,
238 extension_ref,
239 )
240}
241
242pub fn error_type() -> Type {
244 error_custom_type(&Arc::downgrade(&PRELUDE)).into()
245}
246
247pub const ERROR_TYPE_NAME: TypeName = TypeName::new_inline("error");
249
250pub fn sum_with_error(ty: impl Into<TypeRowRV>) -> SumType {
252 either_type(error_type(), ty)
253}
254
255#[inline]
257pub fn option_type(ty: impl Into<TypeRowRV>) -> SumType {
258 either_type(TypeRow::new(), ty)
259}
260
261#[inline]
266pub fn either_type(ty_left: impl Into<TypeRowRV>, ty_right: impl Into<TypeRowRV>) -> SumType {
267 SumType::new([ty_left.into(), ty_right.into()])
268}
269
270pub fn const_some(value: Value) -> Value {
274 const_some_tuple([value])
275}
276
277pub fn const_some_tuple(values: impl IntoIterator<Item = Value>) -> Value {
283 const_right_tuple(TypeRow::new(), values)
284}
285
286pub fn const_none(ty: impl Into<TypeRowRV>) -> Value {
290 const_left_tuple([], ty)
291}
292
293pub fn const_left(value: Value, ty_right: impl Into<TypeRowRV>) -> Value {
299 const_left_tuple([value], ty_right)
300}
301
302pub fn const_left_tuple(
308 values: impl IntoIterator<Item = Value>,
309 ty_right: impl Into<TypeRowRV>,
310) -> Value {
311 let values = values.into_iter().collect_vec();
312 let types: TypeRowRV = values
313 .iter()
314 .map(|v| TypeRV::from(v.get_type()))
315 .collect_vec()
316 .into();
317 let typ = either_type(types, ty_right);
318 Value::sum(0, values, typ).unwrap()
319}
320
321pub fn const_right(ty_left: impl Into<TypeRowRV>, value: Value) -> Value {
327 const_right_tuple(ty_left, [value])
328}
329
330pub fn const_right_tuple(
336 ty_left: impl Into<TypeRowRV>,
337 values: impl IntoIterator<Item = Value>,
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(ty_left, types);
346 Value::sum(1, values, typ).unwrap()
347}
348
349pub fn const_ok(value: Value, ty_fail: impl Into<TypeRowRV>) -> Value {
353 const_right(ty_fail, value)
354}
355
356pub fn const_ok_tuple(
360 values: impl IntoIterator<Item = Value>,
361 ty_fail: impl Into<TypeRowRV>,
362) -> Value {
363 const_right_tuple(ty_fail, values)
364}
365
366pub fn const_fail(value: Value, ty_ok: impl Into<TypeRowRV>) -> Value {
370 const_left(value, ty_ok)
371}
372
373pub fn const_fail_tuple(
377 values: impl IntoIterator<Item = Value>,
378 ty_ok: impl Into<TypeRowRV>,
379) -> Value {
380 const_left_tuple(values, ty_ok)
381}
382
383#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
384pub struct ConstUsize(u64);
386
387impl ConstUsize {
388 pub fn new(value: u64) -> Self {
390 Self(value)
391 }
392
393 pub fn value(&self) -> u64 {
395 self.0
396 }
397}
398
399#[typetag::serde]
400impl CustomConst for ConstUsize {
401 fn name(&self) -> ValueName {
402 format!("ConstUsize({})", self.0).into()
403 }
404
405 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
406 crate::ops::constant::downcast_equal_consts(self, other)
407 }
408
409 fn extension_reqs(&self) -> ExtensionSet {
410 ExtensionSet::singleton(PRELUDE_ID)
411 }
412
413 fn get_type(&self) -> Type {
414 usize_t()
415 }
416}
417
418#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
419pub struct ConstError {
421 pub signal: u32,
423 pub message: String,
425}
426
427impl ConstError {
428 pub fn new(signal: u32, message: impl ToString) -> Self {
430 Self {
431 signal,
432 message: message.to_string(),
433 }
434 }
435
436 pub fn as_either(self, ty_ok: impl Into<TypeRowRV>) -> Value {
441 const_fail(self.into(), ty_ok)
442 }
443}
444
445#[typetag::serde]
446impl CustomConst for ConstError {
447 fn name(&self) -> ValueName {
448 format!("ConstError({}, {:?})", self.signal, self.message).into()
449 }
450
451 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
452 crate::ops::constant::downcast_equal_consts(self, other)
453 }
454
455 fn extension_reqs(&self) -> ExtensionSet {
456 ExtensionSet::singleton(PRELUDE_ID)
457 }
458 fn get_type(&self) -> Type {
459 error_type()
460 }
461}
462
463#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
464pub struct ConstExternalSymbol {
466 pub symbol: String,
468 pub typ: Type,
470 pub constant: bool,
472}
473
474impl ConstExternalSymbol {
475 pub fn new(symbol: impl Into<String>, typ: impl Into<Type>, constant: bool) -> Self {
477 Self {
478 symbol: symbol.into(),
479 typ: typ.into(),
480 constant,
481 }
482 }
483}
484
485impl PartialEq<dyn CustomConst> for ConstExternalSymbol {
486 fn eq(&self, other: &dyn CustomConst) -> bool {
487 self.equal_consts(other)
488 }
489}
490
491#[typetag::serde]
492impl CustomConst for ConstExternalSymbol {
493 fn name(&self) -> ValueName {
494 format!("@{}", &self.symbol).into()
495 }
496
497 fn equal_consts(&self, other: &dyn CustomConst) -> bool {
498 crate::ops::constant::downcast_equal_consts(self, other)
499 }
500
501 fn extension_reqs(&self) -> ExtensionSet {
502 ExtensionSet::singleton(PRELUDE_ID)
503 }
504 fn get_type(&self) -> Type {
505 self.typ.clone()
506 }
507
508 fn update_extensions(
509 &mut self,
510 extensions: &WeakExtensionRegistry,
511 ) -> Result<(), ExtensionResolutionError> {
512 resolve_type_extensions(&mut self.typ, extensions)
513 }
514
515 fn validate(&self) -> Result<(), CustomCheckFailure> {
516 if self.symbol.is_empty() {
517 Err(CustomCheckFailure::Message(
518 "External symbol name is empty.".into(),
519 ))
520 } else {
521 Ok(())
522 }
523 }
524}
525
526#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, EnumIter, IntoStaticStr, EnumString)]
528#[allow(missing_docs)]
529#[non_exhaustive]
530pub enum TupleOpDef {
531 MakeTuple,
532 UnpackTuple,
533}
534
535impl ConstFold for TupleOpDef {
536 fn fold(
537 &self,
538 _type_args: &[TypeArg],
539 consts: &[(crate::IncomingPort, Value)],
540 ) -> crate::extension::ConstFoldResult {
541 match self {
542 TupleOpDef::MakeTuple => {
543 fold_out_row([Value::tuple(sorted_consts(consts).into_iter().cloned())])
544 }
545 TupleOpDef::UnpackTuple => {
546 let c = &consts.first()?.1;
547 let Some(vs) = c.as_tuple() else {
548 panic!("This op always takes a Tuple input.");
549 };
550 fold_out_row(vs.iter().cloned())
551 }
552 }
553 }
554}
555impl MakeOpDef for TupleOpDef {
556 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
557 let rv = TypeRV::new_row_var_use(0, TypeBound::Any);
558 let tuple_type = TypeRV::new_tuple(vec![rv.clone()]);
559
560 let param = TypeParam::new_list(TypeBound::Any);
561 match self {
562 TupleOpDef::MakeTuple => {
563 PolyFuncTypeRV::new([param], FuncValueType::new(rv, tuple_type))
564 }
565 TupleOpDef::UnpackTuple => {
566 PolyFuncTypeRV::new([param], FuncValueType::new(tuple_type, rv))
567 }
568 }
569 .into()
570 }
571
572 fn description(&self) -> String {
573 match self {
574 TupleOpDef::MakeTuple => "MakeTuple operation",
575 TupleOpDef::UnpackTuple => "UnpackTuple operation",
576 }
577 .to_string()
578 }
579
580 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
581 try_from_name(op_def.name(), op_def.extension_id())
582 }
583
584 fn extension(&self) -> ExtensionId {
585 PRELUDE_ID.to_owned()
586 }
587
588 fn extension_ref(&self) -> Weak<Extension> {
589 Arc::downgrade(&PRELUDE)
590 }
591
592 fn post_opdef(&self, def: &mut OpDef) {
593 def.set_constant_folder(*self);
594 }
595}
596#[derive(Debug, Clone, Default, PartialEq, Eq)]
598#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
599#[non_exhaustive]
600pub struct MakeTuple(pub TypeRow);
601
602impl MakeTuple {
603 pub fn new(tys: TypeRow) -> Self {
605 Self(tys)
606 }
607}
608
609impl NamedOp for MakeTuple {
610 fn name(&self) -> OpName {
611 TupleOpDef::MakeTuple.name()
612 }
613}
614
615impl MakeExtensionOp for MakeTuple {
616 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
617 where
618 Self: Sized,
619 {
620 let def = TupleOpDef::from_def(ext_op.def())?;
621 if def != TupleOpDef::MakeTuple {
622 return Err(OpLoadError::NotMember(ext_op.def().name().to_string()))?;
623 }
624 let [TypeArg::Sequence { elems }] = ext_op.args() else {
625 return Err(SignatureError::InvalidTypeArgs)?;
626 };
627 let tys: Result<Vec<Type>, _> = elems
628 .iter()
629 .map(|a| match a {
630 TypeArg::Type { ty } => Ok(ty.clone()),
631 _ => Err(SignatureError::InvalidTypeArgs),
632 })
633 .collect();
634 Ok(Self(tys?.into()))
635 }
636
637 fn type_args(&self) -> Vec<TypeArg> {
638 vec![TypeArg::Sequence {
639 elems: self
640 .0
641 .iter()
642 .map(|t| TypeArg::Type { ty: t.clone() })
643 .collect(),
644 }]
645 }
646}
647
648impl MakeRegisteredOp for MakeTuple {
649 fn extension_id(&self) -> ExtensionId {
650 PRELUDE_ID.to_owned()
651 }
652
653 fn extension_ref(&self) -> Weak<Extension> {
654 Arc::downgrade(&PRELUDE)
655 }
656}
657
658#[derive(Debug, Clone, Default, PartialEq, Eq)]
660#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
661#[non_exhaustive]
662pub struct UnpackTuple(pub TypeRow);
663
664impl UnpackTuple {
665 pub fn new(tys: TypeRow) -> Self {
667 Self(tys)
668 }
669}
670
671impl NamedOp for UnpackTuple {
672 fn name(&self) -> OpName {
673 TupleOpDef::UnpackTuple.name()
674 }
675}
676
677impl MakeExtensionOp for UnpackTuple {
678 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
679 where
680 Self: Sized,
681 {
682 let def = TupleOpDef::from_def(ext_op.def())?;
683 if def != TupleOpDef::UnpackTuple {
684 return Err(OpLoadError::NotMember(ext_op.def().name().to_string()))?;
685 }
686 let [TypeArg::Sequence { elems }] = ext_op.args() else {
687 return Err(SignatureError::InvalidTypeArgs)?;
688 };
689 let tys: Result<Vec<Type>, _> = elems
690 .iter()
691 .map(|a| match a {
692 TypeArg::Type { ty } => Ok(ty.clone()),
693 _ => Err(SignatureError::InvalidTypeArgs),
694 })
695 .collect();
696 Ok(Self(tys?.into()))
697 }
698
699 fn type_args(&self) -> Vec<TypeArg> {
700 vec![TypeArg::Sequence {
701 elems: self
702 .0
703 .iter()
704 .map(|t| TypeArg::Type { ty: t.clone() })
705 .collect(),
706 }]
707 }
708}
709
710impl MakeRegisteredOp for UnpackTuple {
711 fn extension_id(&self) -> ExtensionId {
712 PRELUDE_ID.to_owned()
713 }
714
715 fn extension_ref(&self) -> Weak<Extension> {
716 Arc::downgrade(&PRELUDE)
717 }
718}
719
720#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
721pub struct NoopDef;
723
724impl NamedOp for NoopDef {
725 fn name(&self) -> OpName {
726 "Noop".into()
727 }
728}
729
730impl std::str::FromStr for NoopDef {
731 type Err = ();
732
733 fn from_str(s: &str) -> Result<Self, Self::Err> {
734 if s == NoopDef.name() {
735 Ok(Self)
736 } else {
737 Err(())
738 }
739 }
740}
741impl MakeOpDef for NoopDef {
742 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
743 let tv = Type::new_var_use(0, TypeBound::Any);
744 PolyFuncType::new([TypeBound::Any.into()], Signature::new_endo(tv)).into()
745 }
746
747 fn description(&self) -> String {
748 "Noop gate".to_string()
749 }
750
751 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
752 try_from_name(op_def.name(), op_def.extension_id())
753 }
754
755 fn extension(&self) -> ExtensionId {
756 PRELUDE_ID.to_owned()
757 }
758
759 fn extension_ref(&self) -> Weak<Extension> {
760 Arc::downgrade(&PRELUDE)
761 }
762
763 fn post_opdef(&self, def: &mut OpDef) {
764 def.set_constant_folder(*self);
765 }
766}
767
768impl ConstFold for NoopDef {
769 fn fold(
770 &self,
771 _type_args: &[TypeArg],
772 consts: &[(crate::IncomingPort, Value)],
773 ) -> crate::extension::ConstFoldResult {
774 fold_out_row([consts.first()?.1.clone()])
775 }
776}
777
778#[derive(Debug, Clone, PartialEq, Eq)]
780#[non_exhaustive]
781#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
782pub struct Noop(pub Type);
783
784impl Noop {
785 pub fn new(ty: Type) -> Self {
787 Self(ty)
788 }
789}
790
791impl Default for Noop {
792 fn default() -> Self {
793 Self(Type::UNIT)
794 }
795}
796impl NamedOp for Noop {
797 fn name(&self) -> OpName {
798 NoopDef.name()
799 }
800}
801
802impl MakeExtensionOp for Noop {
803 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
804 where
805 Self: Sized,
806 {
807 let _def = NoopDef::from_def(ext_op.def())?;
808 let [TypeArg::Type { ty }] = ext_op.args() else {
809 return Err(SignatureError::InvalidTypeArgs)?;
810 };
811 Ok(Self(ty.clone()))
812 }
813
814 fn type_args(&self) -> Vec<TypeArg> {
815 vec![TypeArg::Type { ty: self.0.clone() }]
816 }
817}
818
819impl MakeRegisteredOp for Noop {
820 fn extension_id(&self) -> ExtensionId {
821 PRELUDE_ID.to_owned()
822 }
823
824 fn extension_ref(&self) -> Weak<Extension> {
825 Arc::downgrade(&PRELUDE)
826 }
827}
828
829#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
830pub struct LiftDef;
832
833impl NamedOp for LiftDef {
834 fn name(&self) -> OpName {
835 "Lift".into()
836 }
837}
838
839impl std::str::FromStr for LiftDef {
840 type Err = ();
841
842 fn from_str(s: &str) -> Result<Self, Self::Err> {
843 if s == LiftDef.name() {
844 Ok(Self)
845 } else {
846 Err(())
847 }
848 }
849}
850
851impl MakeOpDef for LiftDef {
852 fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
853 PolyFuncTypeRV::new(
854 vec![TypeParam::Extensions, TypeParam::new_list(TypeBound::Any)],
855 FuncValueType::new_endo(TypeRV::new_row_var_use(1, TypeBound::Any))
856 .with_extension_delta(ExtensionSet::type_var(0)),
857 )
858 .into()
859 }
860
861 fn description(&self) -> String {
862 "Add extension requirements to a row of values".to_string()
863 }
864
865 fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
866 try_from_name(op_def.name(), op_def.extension_id())
867 }
868
869 fn extension(&self) -> ExtensionId {
870 PRELUDE_ID.to_owned()
871 }
872
873 fn extension_ref(&self) -> Weak<Extension> {
874 Arc::downgrade(&PRELUDE)
875 }
876}
877
878#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
881#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
882#[non_exhaustive]
883pub struct Lift {
884 pub type_row: TypeRow,
886 pub new_extensions: ExtensionSet,
888}
889
890impl Lift {
891 pub fn new(type_row: TypeRow, set: impl Into<ExtensionSet>) -> Self {
893 Self {
894 type_row,
895 new_extensions: set.into(),
896 }
897 }
898}
899
900impl NamedOp for Lift {
901 fn name(&self) -> OpName {
902 LiftDef.name()
903 }
904}
905
906impl MakeExtensionOp for Lift {
907 fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
908 where
909 Self: Sized,
910 {
911 let _def = LiftDef::from_def(ext_op.def())?;
912
913 let [TypeArg::Extensions { es }, TypeArg::Sequence { elems }] = ext_op.args() else {
914 return Err(SignatureError::InvalidTypeArgs)?;
915 };
916 let tys: Result<Vec<Type>, _> = elems
917 .iter()
918 .map(|a| match a {
919 TypeArg::Type { ty } => Ok(ty.clone()),
920 _ => Err(SignatureError::InvalidTypeArgs),
921 })
922 .collect();
923 Ok(Self {
924 type_row: tys?.into(),
925 new_extensions: es.clone(),
926 })
927 }
928
929 fn type_args(&self) -> Vec<TypeArg> {
930 vec![
931 TypeArg::Extensions {
932 es: self.new_extensions.clone(),
933 },
934 TypeArg::Sequence {
935 elems: self
936 .type_row
937 .iter()
938 .map(|t| TypeArg::Type { ty: t.clone() })
939 .collect(),
940 },
941 ]
942 }
943}
944
945impl MakeRegisteredOp for Lift {
946 fn extension_id(&self) -> ExtensionId {
947 PRELUDE_ID.to_owned()
948 }
949
950 fn extension_ref(&self) -> Weak<Extension> {
951 Arc::downgrade(&PRELUDE)
952 }
953}
954
955#[cfg(test)]
956mod test {
957 use crate::builder::inout_sig;
958 use crate::std_extensions::arithmetic::float_types::{float64_type, ConstF64};
959 use crate::{
960 builder::{endo_sig, DFGBuilder, Dataflow, DataflowHugr},
961 utils::test_quantum_extension::cx_gate,
962 Hugr, Wire,
963 };
964
965 use super::*;
966 use crate::{
967 ops::{OpTrait, OpType},
968 type_row,
969 };
970
971 #[test]
972 fn test_make_tuple() {
973 let op = MakeTuple::new(type_row![Type::UNIT]);
974 let optype: OpType = op.clone().into();
975 assert_eq!(
976 optype.dataflow_signature().unwrap().io(),
977 (
978 &type_row![Type::UNIT],
979 &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
980 )
981 );
982
983 let new_op = MakeTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
984 assert_eq!(new_op, op);
985 }
986
987 #[test]
988 fn test_unmake_tuple() {
989 let op = UnpackTuple::new(type_row![Type::UNIT]);
990 let optype: OpType = op.clone().into();
991 assert_eq!(
992 optype.dataflow_signature().unwrap().io(),
993 (
994 &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
995 &type_row![Type::UNIT],
996 )
997 );
998
999 let new_op = UnpackTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1000 assert_eq!(new_op, op);
1001 }
1002
1003 #[test]
1004 fn test_noop() {
1005 let op = Noop::new(Type::UNIT);
1006 let optype: OpType = op.clone().into();
1007 assert_eq!(
1008 optype.dataflow_signature().unwrap().io(),
1009 (&type_row![Type::UNIT], &type_row![Type::UNIT])
1010 );
1011
1012 let new_op = Noop::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1013 assert_eq!(new_op, op);
1014 }
1015
1016 #[test]
1017 fn test_lift() {
1018 const XA: ExtensionId = ExtensionId::new_unchecked("xa");
1019 let op = Lift::new(type_row![Type::UNIT], ExtensionSet::singleton(XA));
1020 let optype: OpType = op.clone().into();
1021 assert_eq!(
1022 optype.dataflow_signature().unwrap().as_ref(),
1023 &Signature::new_endo(type_row![Type::UNIT])
1024 .with_extension_delta(XA)
1025 .with_prelude()
1026 );
1027
1028 let new_op = Lift::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1029 assert_eq!(new_op, op);
1030 }
1031
1032 #[test]
1033 fn test_option() {
1034 let typ: Type = option_type(bool_t()).into();
1035 let const_val1 = const_some(Value::true_val());
1036 let const_val2 = const_none(bool_t());
1037
1038 let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1039
1040 let some = b.add_load_value(const_val1);
1041 let none = b.add_load_value(const_val2);
1042
1043 b.finish_hugr_with_outputs([some, none]).unwrap();
1044 }
1045
1046 #[test]
1047 fn test_result() {
1048 let typ: Type = either_type(bool_t(), float64_type()).into();
1049 let const_bool = const_left(Value::true_val(), float64_type());
1050 let const_float = const_right(bool_t(), ConstF64::new(0.5).into());
1051
1052 let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1053
1054 let bool = b.add_load_value(const_bool);
1055 let float = b.add_load_value(const_float);
1056
1057 b.finish_hugr_with_outputs([bool, float]).unwrap();
1058 }
1059
1060 #[test]
1061 fn test_error_type() {
1063 let ext_def = PRELUDE
1064 .get_type(&ERROR_TYPE_NAME)
1065 .unwrap()
1066 .instantiate([])
1067 .unwrap();
1068
1069 let ext_type = Type::new_extension(ext_def);
1070 assert_eq!(ext_type, error_type());
1071
1072 let error_val = ConstError::new(2, "my message");
1073
1074 assert_eq!(error_val.name(), "ConstError(2, \"my message\")");
1075
1076 assert!(error_val.validate().is_ok());
1077
1078 assert_eq!(
1079 error_val.extension_reqs(),
1080 ExtensionSet::singleton(PRELUDE_ID)
1081 );
1082 assert!(error_val.equal_consts(&ConstError::new(2, "my message")));
1083 assert!(!error_val.equal_consts(&ConstError::new(3, "my message")));
1084
1085 let mut b = DFGBuilder::new(endo_sig(type_row![])).unwrap();
1086
1087 let err = b.add_load_value(error_val);
1088
1089 const TYPE_ARG_NONE: TypeArg = TypeArg::Sequence { elems: vec![] };
1090 let op = PRELUDE
1091 .instantiate_extension_op(&PANIC_OP_ID, [TYPE_ARG_NONE, TYPE_ARG_NONE])
1092 .unwrap();
1093
1094 b.add_dataflow_op(op, [err]).unwrap();
1095
1096 b.finish_hugr_with_outputs([]).unwrap();
1097 }
1098
1099 #[test]
1100 fn test_panic_with_io() {
1102 let error_val = ConstError::new(42, "PANIC");
1103 let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() };
1104 let type_arg_2q: TypeArg = TypeArg::Sequence {
1105 elems: vec![type_arg_q.clone(), type_arg_q],
1106 };
1107 let panic_op = PRELUDE
1108 .instantiate_extension_op(&PANIC_OP_ID, [type_arg_2q.clone(), type_arg_2q.clone()])
1109 .unwrap();
1110
1111 let mut b = DFGBuilder::new(endo_sig(vec![qb_t(), qb_t()])).unwrap();
1112 let [q0, q1] = b.input_wires_arr();
1113 let [q0, q1] = b
1114 .add_dataflow_op(cx_gate(), [q0, q1])
1115 .unwrap()
1116 .outputs_arr();
1117 let err = b.add_load_value(error_val);
1118 let [q0, q1] = b
1119 .add_dataflow_op(panic_op, [err, q0, q1])
1120 .unwrap()
1121 .outputs_arr();
1122 b.finish_hugr_with_outputs([q0, q1]).unwrap();
1123 }
1124
1125 #[test]
1126 fn test_string_type() {
1128 let string_custom_type: CustomType = PRELUDE
1129 .get_type(&STRING_TYPE_NAME)
1130 .unwrap()
1131 .instantiate([])
1132 .unwrap();
1133 let string_ty: Type = Type::new_extension(string_custom_type);
1134 assert_eq!(string_ty, string_type());
1135 let string_const: ConstString = ConstString::new("Lorem ipsum".into());
1136 assert_eq!(string_const.name(), "ConstString(\"Lorem ipsum\")");
1137 assert!(string_const.validate().is_ok());
1138 assert_eq!(
1139 string_const.extension_reqs(),
1140 ExtensionSet::singleton(PRELUDE_ID)
1141 );
1142 assert!(string_const.equal_consts(&ConstString::new("Lorem ipsum".into())));
1143 assert!(!string_const.equal_consts(&ConstString::new("Lorem ispum".into())));
1144 }
1145
1146 #[test]
1147 fn test_print() {
1149 let mut b: DFGBuilder<Hugr> = DFGBuilder::new(endo_sig(vec![])).unwrap();
1150 let greeting: ConstString = ConstString::new("Hello, world!".into());
1151 let greeting_out: Wire = b.add_load_value(greeting);
1152 let print_op = PRELUDE.instantiate_extension_op(&PRINT_OP_ID, []).unwrap();
1153 b.add_dataflow_op(print_op, [greeting_out]).unwrap();
1154 b.finish_hugr_with_outputs([]).unwrap();
1155 }
1156
1157 #[test]
1158 fn test_external_symbol() {
1159 let subject = ConstExternalSymbol::new("foo", Type::UNIT, false);
1160 assert_eq!(subject.get_type(), Type::UNIT);
1161 assert_eq!(subject.name(), "@foo");
1162 assert!(subject.validate().is_ok());
1163 assert_eq!(
1164 subject.extension_reqs(),
1165 ExtensionSet::singleton(PRELUDE_ID)
1166 );
1167 assert!(subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, false)));
1168 assert!(!subject.equal_consts(&ConstExternalSymbol::new("bar", Type::UNIT, false)));
1169 assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", string_type(), false)));
1170 assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, true)));
1171
1172 assert!(ConstExternalSymbol::new("", Type::UNIT, true)
1173 .validate()
1174 .is_err())
1175 }
1176}