hugr_core/extension/
prelude.rs

1//! Prelude extension - available in all contexts, defining common types,
2//! operations and constants.
3use 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
35/// Operation to load generic bounded nat parameter.
36pub mod generic;
37
38/// Name of prelude extension.
39pub const PRELUDE_ID: ExtensionId = ExtensionId::new_unchecked("prelude");
40/// Extension version.
41pub const VERSION: semver::Version = semver::Version::new(0, 2, 0);
42lazy_static! {
43    /// Prelude extension, containing common types and operations.
44    pub static ref PRELUDE: Arc<Extension> = {
45        Extension::new_arc(PRELUDE_ID, VERSION, |prelude, extension_ref| {
46
47            // Construct the list and error types using the passed extension
48            // reference.
49            //
50            // If we tried to use `string_type()` or `error_type()` directly it
51            // would try to access the `PRELUDE` lazy static recursively,
52            // causing a deadlock.
53            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            BarrierDef.add_to_extension(prelude, extension_ref).unwrap();
116            generic::LoadNatDef.add_to_extension(prelude, extension_ref).unwrap();
117        })
118    };
119
120    /// An extension registry containing only the prelude
121    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
144/// Qubit type.
145pub fn qb_t() -> Type {
146    qb_custom_t(&Arc::downgrade(&PRELUDE)).into()
147}
148/// Unsigned size type.
149pub fn usize_t() -> Type {
150    usize_custom_t(&Arc::downgrade(&PRELUDE)).into()
151}
152/// Boolean type - Sum of two units.
153pub fn bool_t() -> Type {
154    Type::new_unit_sum(2)
155}
156
157/// Name of the prelude panic operation.
158///
159/// This operation can have any input and any output wires; it is instantiated
160/// with two [TypeArg::Sequence]s representing these. The first input to the
161/// operation is always an error type; the remaining inputs correspond to the
162/// first sequence of types in its instantiation; the outputs correspond to the
163/// second sequence of types in its instantiation. Note that the inputs and
164/// outputs only exist so that structural constraints such as linearity can be
165/// satisfied.
166pub const PANIC_OP_ID: OpName = OpName::new_inline("panic");
167
168/// Name of the string type.
169pub const STRING_TYPE_NAME: TypeName = TypeName::new_inline("string");
170
171/// Custom type for strings.
172///
173/// Receives a reference to the prelude extensions as a parameter.
174/// This avoids deadlocks when we are in the process of creating the prelude.
175fn 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
185/// String type.
186pub fn string_type() -> Type {
187    string_custom_type(&Arc::downgrade(&PRELUDE)).into()
188}
189
190#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
191/// Structure for holding constant string values.
192pub struct ConstString(String);
193
194impl ConstString {
195    /// Creates a new [`ConstString`].
196    pub fn new(value: String) -> Self {
197        Self(value)
198    }
199
200    /// Returns the value of the constant.
201    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
225/// Name of the print operation
226pub const PRINT_OP_ID: OpName = OpName::new_inline("print");
227
228/// The custom type for Errors.
229///
230/// Receives a reference to the prelude extensions as a parameter.
231/// This avoids deadlocks when we are in the process of creating the prelude.
232fn 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
242/// Unspecified opaque error type.
243pub fn error_type() -> Type {
244    error_custom_type(&Arc::downgrade(&PRELUDE)).into()
245}
246
247/// The string name of the error type.
248pub const ERROR_TYPE_NAME: TypeName = TypeName::new_inline("error");
249
250/// Return a Sum type with the second variant as the given type and the first an Error.
251pub fn sum_with_error(ty: impl Into<TypeRowRV>) -> SumType {
252    either_type(error_type(), ty)
253}
254
255/// An optional type, i.e. a Sum type with the second variant as the given type and the first as an empty tuple.
256#[inline]
257pub fn option_type(ty: impl Into<TypeRowRV>) -> SumType {
258    either_type(TypeRow::new(), ty)
259}
260
261/// An "either" type, i.e. a Sum type with a "left" and a "right" variant.
262///
263/// When used as a fallible value, the "right" variant represents a successful computation,
264/// and the "left" variant represents a failure.
265#[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
270/// A constant optional value with a given value.
271///
272/// See [option_type].
273pub fn const_some(value: Value) -> Value {
274    const_some_tuple([value])
275}
276
277/// A constant optional value with a row of values.
278///
279/// For single values, use [const_some].
280///
281/// See [option_type].
282pub fn const_some_tuple(values: impl IntoIterator<Item = Value>) -> Value {
283    const_right_tuple(TypeRow::new(), values)
284}
285
286/// A constant optional value with no value.
287///
288/// See [option_type].
289pub fn const_none(ty: impl Into<TypeRowRV>) -> Value {
290    const_left_tuple([], ty)
291}
292
293/// A constant Either value with a left variant.
294///
295/// In fallible computations, this represents a failure.
296///
297/// See [either_type].
298pub fn const_left(value: Value, ty_right: impl Into<TypeRowRV>) -> Value {
299    const_left_tuple([value], ty_right)
300}
301
302/// A constant Either value with a row of left values.
303///
304/// In fallible computations, this represents a failure.
305///
306/// See [either_type].
307pub 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
321/// A constant Either value with a right variant.
322///
323/// In fallible computations, this represents a successful result.
324///
325/// See [either_type].
326pub fn const_right(ty_left: impl Into<TypeRowRV>, value: Value) -> Value {
327    const_right_tuple(ty_left, [value])
328}
329
330/// A constant Either value with a row of right values.
331///
332/// In fallible computations, this represents a successful result.
333///
334/// See [either_type].
335pub 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
349/// A constant Either value with a success variant.
350///
351/// Alias for [const_right].
352pub fn const_ok(value: Value, ty_fail: impl Into<TypeRowRV>) -> Value {
353    const_right(ty_fail, value)
354}
355
356/// A constant Either with a row of success values.
357///
358/// Alias for [const_right_tuple].
359pub 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
366/// A constant Either value with a failure variant.
367///
368/// Alias for [const_left].
369pub fn const_fail(value: Value, ty_ok: impl Into<TypeRowRV>) -> Value {
370    const_left(value, ty_ok)
371}
372
373/// A constant Either with a row of failure values.
374///
375/// Alias for [const_left_tuple].
376pub 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)]
384/// Structure for holding constant usize values.
385pub struct ConstUsize(u64);
386
387impl ConstUsize {
388    /// Creates a new [`ConstUsize`].
389    pub fn new(value: u64) -> Self {
390        Self(value)
391    }
392
393    /// Returns the value of the constant.
394    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)]
419/// Structure for holding constant usize values.
420pub struct ConstError {
421    /// Integer tag/signal for the error.
422    pub signal: u32,
423    /// Error message.
424    pub message: String,
425}
426
427impl ConstError {
428    /// Define a new error value.
429    pub fn new(signal: u32, message: impl ToString) -> Self {
430        Self {
431            signal,
432            message: message.to_string(),
433        }
434    }
435
436    /// Returns an "either" value with a failure variant.
437    ///
438    /// args:
439    ///     ty_ok: The type of the success variant.
440    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)]
464/// A structure for holding references to external symbols.
465pub struct ConstExternalSymbol {
466    /// The symbol name that this value refers to. Must be nonempty.
467    pub symbol: String,
468    /// The type of the value found at this symbol reference.
469    pub typ: Type,
470    /// Whether the value at the symbol reference is constant or mutable.
471    pub constant: bool,
472}
473
474impl ConstExternalSymbol {
475    /// Construct a new [ConstExternalSymbol].
476    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/// Logic extension operation definitions.
527#[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/// An operation that packs all its inputs into a tuple.
597#[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    /// Create a new MakeTuple operation.
604    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/// An operation that unpacks a tuple into its components.
659#[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    /// Create a new UnpackTuple operation.
666    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)]
721/// A no-op operation definition.
722pub 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/// A no-op operation.
779#[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    /// Create a new Noop operation.
786    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)]
830/// A barrier operation definition.
831pub struct BarrierDef;
832
833/// Name of the barrier operation.
834pub const BARRIER_OP_ID: OpName = OpName::new_inline("Barrier");
835impl NamedOp for BarrierDef {
836    fn name(&self) -> OpName {
837        BARRIER_OP_ID
838    }
839}
840
841impl std::str::FromStr for BarrierDef {
842    type Err = ();
843
844    fn from_str(s: &str) -> Result<Self, Self::Err> {
845        if s == BarrierDef.name() {
846            Ok(Self)
847        } else {
848            Err(())
849        }
850    }
851}
852
853impl MakeOpDef for BarrierDef {
854    fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
855        PolyFuncTypeRV::new(
856            vec![TypeParam::new_list(TypeBound::Any)],
857            FuncValueType::new_endo(TypeRV::new_row_var_use(0, TypeBound::Any)),
858        )
859        .into()
860    }
861
862    fn description(&self) -> String {
863        "Add a barrier to a row of values".to_string()
864    }
865
866    fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
867        try_from_name(op_def.name(), op_def.extension_id())
868    }
869
870    fn extension(&self) -> ExtensionId {
871        PRELUDE_ID.to_owned()
872    }
873
874    fn extension_ref(&self) -> Weak<Extension> {
875        Arc::downgrade(&PRELUDE)
876    }
877}
878
879/// A barrier across a row of values. This operation has no effect on the values,
880/// except to enforce some ordering between operations before and after the barrier.
881#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
882#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
883#[non_exhaustive]
884pub struct Barrier {
885    /// The types of the edges
886    pub type_row: TypeRow,
887}
888
889impl Barrier {
890    /// Create a new Barrier operation over the specified row.
891    pub fn new(type_row: impl Into<TypeRow>) -> Self {
892        Self {
893            type_row: type_row.into(),
894        }
895    }
896}
897
898impl NamedOp for Barrier {
899    fn name(&self) -> OpName {
900        BarrierDef.name()
901    }
902}
903
904impl MakeExtensionOp for Barrier {
905    fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
906    where
907        Self: Sized,
908    {
909        let _def = BarrierDef::from_def(ext_op.def())?;
910
911        let [TypeArg::Sequence { elems }] = ext_op.args() else {
912            return Err(SignatureError::InvalidTypeArgs)?;
913        };
914        let tys: Result<Vec<Type>, _> = elems
915            .iter()
916            .map(|a| match a {
917                TypeArg::Type { ty } => Ok(ty.clone()),
918                _ => Err(SignatureError::InvalidTypeArgs),
919            })
920            .collect();
921        Ok(Self {
922            type_row: tys?.into(),
923        })
924    }
925
926    fn type_args(&self) -> Vec<TypeArg> {
927        vec![TypeArg::Sequence {
928            elems: self
929                .type_row
930                .iter()
931                .map(|t| TypeArg::Type { ty: t.clone() })
932                .collect(),
933        }]
934    }
935}
936
937impl MakeRegisteredOp for Barrier {
938    fn extension_id(&self) -> ExtensionId {
939        PRELUDE_ID.to_owned()
940    }
941
942    fn extension_ref(&self) -> Weak<Extension> {
943        Arc::downgrade(&PRELUDE)
944    }
945}
946
947#[cfg(test)]
948mod test {
949    use crate::builder::inout_sig;
950    use crate::std_extensions::arithmetic::float_types::{float64_type, ConstF64};
951    use crate::{
952        builder::{endo_sig, DFGBuilder, Dataflow, DataflowHugr},
953        utils::test_quantum_extension::cx_gate,
954        Hugr, Wire,
955    };
956
957    use super::*;
958    use crate::{
959        ops::{OpTrait, OpType},
960        type_row,
961    };
962
963    #[test]
964    fn test_make_tuple() {
965        let op = MakeTuple::new(type_row![Type::UNIT]);
966        let optype: OpType = op.clone().into();
967        assert_eq!(
968            optype.dataflow_signature().unwrap().io(),
969            (
970                &type_row![Type::UNIT],
971                &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
972            )
973        );
974
975        let new_op = MakeTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
976        assert_eq!(new_op, op);
977    }
978
979    #[test]
980    fn test_unmake_tuple() {
981        let op = UnpackTuple::new(type_row![Type::UNIT]);
982        let optype: OpType = op.clone().into();
983        assert_eq!(
984            optype.dataflow_signature().unwrap().io(),
985            (
986                &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
987                &type_row![Type::UNIT],
988            )
989        );
990
991        let new_op = UnpackTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
992        assert_eq!(new_op, op);
993    }
994
995    #[test]
996    fn test_noop() {
997        let op = Noop::new(Type::UNIT);
998        let optype: OpType = op.clone().into();
999        assert_eq!(
1000            optype.dataflow_signature().unwrap().io(),
1001            (&type_row![Type::UNIT], &type_row![Type::UNIT])
1002        );
1003
1004        let new_op = Noop::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1005        assert_eq!(new_op, op);
1006    }
1007
1008    #[test]
1009    fn test_lift() {
1010        let op = Barrier::new(type_row![Type::UNIT]);
1011        let optype: OpType = op.clone().into();
1012        assert_eq!(
1013            optype.dataflow_signature().unwrap().as_ref(),
1014            &Signature::new_endo(type_row![Type::UNIT]).with_prelude()
1015        );
1016
1017        let new_op = Barrier::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1018        assert_eq!(new_op, op);
1019    }
1020
1021    #[test]
1022    fn test_option() {
1023        let typ: Type = option_type(bool_t()).into();
1024        let const_val1 = const_some(Value::true_val());
1025        let const_val2 = const_none(bool_t());
1026
1027        let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1028
1029        let some = b.add_load_value(const_val1);
1030        let none = b.add_load_value(const_val2);
1031
1032        b.finish_hugr_with_outputs([some, none]).unwrap();
1033    }
1034
1035    #[test]
1036    fn test_result() {
1037        let typ: Type = either_type(bool_t(), float64_type()).into();
1038        let const_bool = const_left(Value::true_val(), float64_type());
1039        let const_float = const_right(bool_t(), ConstF64::new(0.5).into());
1040
1041        let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1042
1043        let bool = b.add_load_value(const_bool);
1044        let float = b.add_load_value(const_float);
1045
1046        b.finish_hugr_with_outputs([bool, float]).unwrap();
1047    }
1048
1049    #[test]
1050    /// test the prelude error type and panic op.
1051    fn test_error_type() {
1052        let ext_def = PRELUDE
1053            .get_type(&ERROR_TYPE_NAME)
1054            .unwrap()
1055            .instantiate([])
1056            .unwrap();
1057
1058        let ext_type = Type::new_extension(ext_def);
1059        assert_eq!(ext_type, error_type());
1060
1061        let error_val = ConstError::new(2, "my message");
1062
1063        assert_eq!(error_val.name(), "ConstError(2, \"my message\")");
1064
1065        assert!(error_val.validate().is_ok());
1066
1067        assert_eq!(
1068            error_val.extension_reqs(),
1069            ExtensionSet::singleton(PRELUDE_ID)
1070        );
1071        assert!(error_val.equal_consts(&ConstError::new(2, "my message")));
1072        assert!(!error_val.equal_consts(&ConstError::new(3, "my message")));
1073
1074        let mut b = DFGBuilder::new(endo_sig(type_row![])).unwrap();
1075
1076        let err = b.add_load_value(error_val);
1077
1078        const TYPE_ARG_NONE: TypeArg = TypeArg::Sequence { elems: vec![] };
1079        let op = PRELUDE
1080            .instantiate_extension_op(&PANIC_OP_ID, [TYPE_ARG_NONE, TYPE_ARG_NONE])
1081            .unwrap();
1082
1083        b.add_dataflow_op(op, [err]).unwrap();
1084
1085        b.finish_hugr_with_outputs([]).unwrap();
1086    }
1087
1088    #[test]
1089    /// test the panic operation with input and output wires
1090    fn test_panic_with_io() {
1091        let error_val = ConstError::new(42, "PANIC");
1092        let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() };
1093        let type_arg_2q: TypeArg = TypeArg::Sequence {
1094            elems: vec![type_arg_q.clone(), type_arg_q],
1095        };
1096        let panic_op = PRELUDE
1097            .instantiate_extension_op(&PANIC_OP_ID, [type_arg_2q.clone(), type_arg_2q.clone()])
1098            .unwrap();
1099
1100        let mut b = DFGBuilder::new(endo_sig(vec![qb_t(), qb_t()])).unwrap();
1101        let [q0, q1] = b.input_wires_arr();
1102        let [q0, q1] = b
1103            .add_dataflow_op(cx_gate(), [q0, q1])
1104            .unwrap()
1105            .outputs_arr();
1106        let err = b.add_load_value(error_val);
1107        let [q0, q1] = b
1108            .add_dataflow_op(panic_op, [err, q0, q1])
1109            .unwrap()
1110            .outputs_arr();
1111        b.finish_hugr_with_outputs([q0, q1]).unwrap();
1112    }
1113
1114    #[test]
1115    /// Test string type.
1116    fn test_string_type() {
1117        let string_custom_type: CustomType = PRELUDE
1118            .get_type(&STRING_TYPE_NAME)
1119            .unwrap()
1120            .instantiate([])
1121            .unwrap();
1122        let string_ty: Type = Type::new_extension(string_custom_type);
1123        assert_eq!(string_ty, string_type());
1124        let string_const: ConstString = ConstString::new("Lorem ipsum".into());
1125        assert_eq!(string_const.name(), "ConstString(\"Lorem ipsum\")");
1126        assert!(string_const.validate().is_ok());
1127        assert_eq!(
1128            string_const.extension_reqs(),
1129            ExtensionSet::singleton(PRELUDE_ID)
1130        );
1131        assert!(string_const.equal_consts(&ConstString::new("Lorem ipsum".into())));
1132        assert!(!string_const.equal_consts(&ConstString::new("Lorem ispum".into())));
1133    }
1134
1135    #[test]
1136    /// Test print operation
1137    fn test_print() {
1138        let mut b: DFGBuilder<Hugr> = DFGBuilder::new(endo_sig(vec![])).unwrap();
1139        let greeting: ConstString = ConstString::new("Hello, world!".into());
1140        let greeting_out: Wire = b.add_load_value(greeting);
1141        let print_op = PRELUDE.instantiate_extension_op(&PRINT_OP_ID, []).unwrap();
1142        b.add_dataflow_op(print_op, [greeting_out]).unwrap();
1143        b.finish_hugr_with_outputs([]).unwrap();
1144    }
1145
1146    #[test]
1147    fn test_external_symbol() {
1148        let subject = ConstExternalSymbol::new("foo", Type::UNIT, false);
1149        assert_eq!(subject.get_type(), Type::UNIT);
1150        assert_eq!(subject.name(), "@foo");
1151        assert!(subject.validate().is_ok());
1152        assert_eq!(
1153            subject.extension_reqs(),
1154            ExtensionSet::singleton(PRELUDE_ID)
1155        );
1156        assert!(subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, false)));
1157        assert!(!subject.equal_consts(&ConstExternalSymbol::new("bar", Type::UNIT, false)));
1158        assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", string_type(), false)));
1159        assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, true)));
1160
1161        assert!(ConstExternalSymbol::new("", Type::UNIT, true)
1162            .validate()
1163            .is_err())
1164    }
1165}