hugr_core/extension/
prelude.rs

1//! Prelude extension - available in all contexts, defining common types,
2//! operations and constants.
3use std::str::FromStr;
4use std::sync::{Arc, Weak};
5
6use itertools::Itertools;
7use lazy_static::lazy_static;
8
9use crate::extension::const_fold::fold_out_row;
10use crate::extension::simple_op::{
11    try_from_name, MakeExtensionOp, MakeOpDef, MakeRegisteredOp, OpLoadError,
12};
13use crate::extension::{
14    ConstFold, ExtensionId, OpDef, SignatureError, SignatureFunc, TypeDefBound,
15};
16use crate::ops::constant::{CustomCheckFailure, CustomConst, ValueName};
17use crate::ops::OpName;
18use crate::ops::{NamedOp, Value};
19use crate::types::type_param::{TypeArg, TypeParam};
20use crate::types::{
21    CustomType, FuncValueType, PolyFuncType, PolyFuncTypeRV, Signature, SumType, Type, TypeBound,
22    TypeName, TypeRV, TypeRow, TypeRowRV,
23};
24use crate::utils::sorted_consts;
25use crate::{type_row, Extension};
26
27use strum::{EnumIter, EnumString, IntoStaticStr};
28
29use super::resolution::{resolve_type_extensions, ExtensionResolutionError, WeakExtensionRegistry};
30use super::ExtensionRegistry;
31
32mod unwrap_builder;
33
34pub use unwrap_builder::UnwrapBuilder;
35
36/// Operation to load generic bounded nat parameter.
37pub mod generic;
38
39/// Name of prelude extension.
40pub const PRELUDE_ID: ExtensionId = ExtensionId::new_unchecked("prelude");
41/// Extension version.
42pub const VERSION: semver::Version = semver::Version::new(0, 2, 0);
43lazy_static! {
44    /// Prelude extension, containing common types and operations.
45    pub static ref PRELUDE: Arc<Extension> = {
46        Extension::new_arc(PRELUDE_ID, VERSION, |prelude, extension_ref| {
47
48            // Construct the list and error types using the passed extension
49            // reference.
50            //
51            // If we tried to use `string_type()` or `error_type()` directly it
52            // would try to access the `PRELUDE` lazy static recursively,
53            // causing a deadlock.
54            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    /// An extension registry containing only the prelude
136    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
159/// Qubit type.
160pub fn qb_t() -> Type {
161    qb_custom_t(&Arc::downgrade(&PRELUDE)).into()
162}
163/// Unsigned size type.
164pub fn usize_t() -> Type {
165    usize_custom_t(&Arc::downgrade(&PRELUDE)).into()
166}
167/// Boolean type - Sum of two units.
168pub fn bool_t() -> Type {
169    Type::new_unit_sum(2)
170}
171
172/// Name of the prelude panic operation.
173///
174/// This operation can have any input and any output wires; it is instantiated
175/// with two [TypeArg::Sequence]s representing these. The first input to the
176/// operation is always an error type; the remaining inputs correspond to the
177/// first sequence of types in its instantiation; the outputs correspond to the
178/// second sequence of types in its instantiation. Note that the inputs and
179/// outputs only exist so that structural constraints such as linearity can be
180/// satisfied.
181///
182/// Panic immediately halts a multi-shot program. It is intended to be used in
183/// cases where an unrecoverable error is detected.
184pub const PANIC_OP_ID: OpName = OpName::new_inline("panic");
185
186/// Name of the prelude exit operation.
187///
188/// This operation can have any input and any output wires; it is instantiated
189/// with two [TypeArg::Sequence]s representing these. The first input to the
190/// operation is always an error type; the remaining inputs correspond to the
191/// first sequence of types in its instantiation; the outputs correspond to the
192/// second sequence of types in its instantiation. Note that the inputs and
193/// outputs only exist so that structural constraints such as linearity can be
194/// satisfied.
195///
196/// Exit immediately halts a single shot's execution. It is intended to be used
197/// when the user wants to exit the program early.
198pub const EXIT_OP_ID: OpName = OpName::new_inline("exit");
199
200/// Name of the string type.
201pub const STRING_TYPE_NAME: TypeName = TypeName::new_inline("string");
202
203/// Custom type for strings.
204///
205/// Receives a reference to the prelude extensions as a parameter.
206/// This avoids deadlocks when we are in the process of creating the prelude.
207fn 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
217/// String type.
218pub fn string_type() -> Type {
219    string_custom_type(&Arc::downgrade(&PRELUDE)).into()
220}
221
222#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
223/// Structure for holding constant string values.
224pub struct ConstString(String);
225
226impl ConstString {
227    /// Creates a new [`ConstString`].
228    pub fn new(value: String) -> Self {
229        Self(value)
230    }
231
232    /// Returns the value of the constant.
233    pub fn value(&self) -> &str {
234        &self.0
235    }
236}
237
238#[typetag::serde]
239impl CustomConst for ConstString {
240    fn name(&self) -> ValueName {
241        format!("ConstString({:?})", self.0).into()
242    }
243
244    fn equal_consts(&self, other: &dyn CustomConst) -> bool {
245        crate::ops::constant::downcast_equal_consts(self, other)
246    }
247
248    fn get_type(&self) -> Type {
249        string_type()
250    }
251}
252
253/// Name of the print operation
254pub const PRINT_OP_ID: OpName = OpName::new_inline("print");
255
256/// The custom type for Errors.
257///
258/// Receives a reference to the prelude extensions as a parameter.
259/// This avoids deadlocks when we are in the process of creating the prelude.
260fn error_custom_type(extension_ref: &Weak<Extension>) -> CustomType {
261    CustomType::new(
262        ERROR_TYPE_NAME,
263        vec![],
264        PRELUDE_ID,
265        TypeBound::Copyable,
266        extension_ref,
267    )
268}
269
270/// Unspecified opaque error type.
271pub fn error_type() -> Type {
272    error_custom_type(&Arc::downgrade(&PRELUDE)).into()
273}
274
275/// The string name of the error type.
276pub const ERROR_TYPE_NAME: TypeName = TypeName::new_inline("error");
277
278/// Return a Sum type with the second variant as the given type and the first an Error.
279pub fn sum_with_error(ty: impl Into<TypeRowRV>) -> SumType {
280    either_type(error_type(), ty)
281}
282
283/// An optional type, i.e. a Sum type with the second variant as the given type and the first as an empty tuple.
284#[inline]
285pub fn option_type(ty: impl Into<TypeRowRV>) -> SumType {
286    either_type(TypeRow::new(), ty)
287}
288
289/// An "either" type, i.e. a Sum type with a "left" and a "right" variant.
290///
291/// When used as a fallible value, the "right" variant represents a successful computation,
292/// and the "left" variant represents a failure.
293#[inline]
294pub fn either_type(ty_left: impl Into<TypeRowRV>, ty_right: impl Into<TypeRowRV>) -> SumType {
295    SumType::new([ty_left.into(), ty_right.into()])
296}
297
298/// A constant optional value with a given value.
299///
300/// See [option_type].
301pub fn const_some(value: Value) -> Value {
302    const_some_tuple([value])
303}
304
305/// A constant optional value with a row of values.
306///
307/// For single values, use [const_some].
308///
309/// See [option_type].
310pub fn const_some_tuple(values: impl IntoIterator<Item = Value>) -> Value {
311    const_right_tuple(TypeRow::new(), values)
312}
313
314/// A constant optional value with no value.
315///
316/// See [option_type].
317pub fn const_none(ty: impl Into<TypeRowRV>) -> Value {
318    const_left_tuple([], ty)
319}
320
321/// A constant Either value with a left variant.
322///
323/// In fallible computations, this represents a failure.
324///
325/// See [either_type].
326pub fn const_left(value: Value, ty_right: impl Into<TypeRowRV>) -> Value {
327    const_left_tuple([value], ty_right)
328}
329
330/// A constant Either value with a row of left values.
331///
332/// In fallible computations, this represents a failure.
333///
334/// See [either_type].
335pub fn const_left_tuple(
336    values: impl IntoIterator<Item = Value>,
337    ty_right: impl Into<TypeRowRV>,
338) -> Value {
339    let values = values.into_iter().collect_vec();
340    let types: TypeRowRV = values
341        .iter()
342        .map(|v| TypeRV::from(v.get_type()))
343        .collect_vec()
344        .into();
345    let typ = either_type(types, ty_right);
346    Value::sum(0, values, typ).unwrap()
347}
348
349/// A constant Either value with a right variant.
350///
351/// In fallible computations, this represents a successful result.
352///
353/// See [either_type].
354pub fn const_right(ty_left: impl Into<TypeRowRV>, value: Value) -> Value {
355    const_right_tuple(ty_left, [value])
356}
357
358/// A constant Either value with a row of right values.
359///
360/// In fallible computations, this represents a successful result.
361///
362/// See [either_type].
363pub fn const_right_tuple(
364    ty_left: impl Into<TypeRowRV>,
365    values: impl IntoIterator<Item = Value>,
366) -> Value {
367    let values = values.into_iter().collect_vec();
368    let types: TypeRowRV = values
369        .iter()
370        .map(|v| TypeRV::from(v.get_type()))
371        .collect_vec()
372        .into();
373    let typ = either_type(ty_left, types);
374    Value::sum(1, values, typ).unwrap()
375}
376
377/// A constant Either value with a success variant.
378///
379/// Alias for [const_right].
380pub fn const_ok(value: Value, ty_fail: impl Into<TypeRowRV>) -> Value {
381    const_right(ty_fail, value)
382}
383
384/// A constant Either with a row of success values.
385///
386/// Alias for [const_right_tuple].
387pub fn const_ok_tuple(
388    values: impl IntoIterator<Item = Value>,
389    ty_fail: impl Into<TypeRowRV>,
390) -> Value {
391    const_right_tuple(ty_fail, values)
392}
393
394/// A constant Either value with a failure variant.
395///
396/// Alias for [const_left].
397pub fn const_fail(value: Value, ty_ok: impl Into<TypeRowRV>) -> Value {
398    const_left(value, ty_ok)
399}
400
401/// A constant Either with a row of failure values.
402///
403/// Alias for [const_left_tuple].
404pub fn const_fail_tuple(
405    values: impl IntoIterator<Item = Value>,
406    ty_ok: impl Into<TypeRowRV>,
407) -> Value {
408    const_left_tuple(values, ty_ok)
409}
410
411#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
412/// Structure for holding constant usize values.
413pub struct ConstUsize(u64);
414
415impl ConstUsize {
416    /// Creates a new [`ConstUsize`].
417    pub fn new(value: u64) -> Self {
418        Self(value)
419    }
420
421    /// Returns the value of the constant.
422    pub fn value(&self) -> u64 {
423        self.0
424    }
425}
426
427#[typetag::serde]
428impl CustomConst for ConstUsize {
429    fn name(&self) -> ValueName {
430        format!("ConstUsize({})", self.0).into()
431    }
432
433    fn equal_consts(&self, other: &dyn CustomConst) -> bool {
434        crate::ops::constant::downcast_equal_consts(self, other)
435    }
436
437    fn get_type(&self) -> Type {
438        usize_t()
439    }
440}
441
442#[derive(Debug, Clone, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
443/// Structure for holding constant [error types].
444///
445/// [error types]: crate::extension::prelude::error_type
446pub struct ConstError {
447    /// Integer tag/signal for the error.
448    pub signal: u32,
449    /// Error message.
450    pub message: String,
451}
452
453/// Default error signal.
454pub const DEFAULT_ERROR_SIGNAL: u32 = 1;
455
456impl ConstError {
457    /// Define a new error value.
458    pub fn new(signal: u32, message: impl ToString) -> Self {
459        Self {
460            signal,
461            message: message.to_string(),
462        }
463    }
464
465    /// Define a new error value with the [default signal].
466    ///
467    /// [default signal]: DEFAULT_ERROR_SIGNAL
468    pub fn new_default_signal(message: impl ToString) -> Self {
469        Self::new(DEFAULT_ERROR_SIGNAL, message)
470    }
471    /// Returns an "either" value with a failure variant.
472    ///
473    /// args:
474    ///     ty_ok: The type of the success variant.
475    pub fn as_either(self, ty_ok: impl Into<TypeRowRV>) -> Value {
476        const_fail(self.into(), ty_ok)
477    }
478}
479
480#[typetag::serde]
481impl CustomConst for ConstError {
482    fn name(&self) -> ValueName {
483        format!("ConstError({}, {:?})", self.signal, self.message).into()
484    }
485
486    fn equal_consts(&self, other: &dyn CustomConst) -> bool {
487        crate::ops::constant::downcast_equal_consts(self, other)
488    }
489
490    fn get_type(&self) -> Type {
491        error_type()
492    }
493}
494
495impl FromStr for ConstError {
496    type Err = ();
497
498    fn from_str(s: &str) -> Result<Self, Self::Err> {
499        Ok(Self::new_default_signal(s))
500    }
501}
502
503impl From<String> for ConstError {
504    fn from(s: String) -> Self {
505        Self::new_default_signal(s)
506    }
507}
508
509#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
510/// A structure for holding references to external symbols.
511pub struct ConstExternalSymbol {
512    /// The symbol name that this value refers to. Must be nonempty.
513    pub symbol: String,
514    /// The type of the value found at this symbol reference.
515    pub typ: Type,
516    /// Whether the value at the symbol reference is constant or mutable.
517    pub constant: bool,
518}
519
520impl ConstExternalSymbol {
521    /// Construct a new [ConstExternalSymbol].
522    pub fn new(symbol: impl Into<String>, typ: impl Into<Type>, constant: bool) -> Self {
523        Self {
524            symbol: symbol.into(),
525            typ: typ.into(),
526            constant,
527        }
528    }
529}
530
531impl PartialEq<dyn CustomConst> for ConstExternalSymbol {
532    fn eq(&self, other: &dyn CustomConst) -> bool {
533        self.equal_consts(other)
534    }
535}
536
537#[typetag::serde]
538impl CustomConst for ConstExternalSymbol {
539    fn name(&self) -> ValueName {
540        format!("@{}", &self.symbol).into()
541    }
542
543    fn equal_consts(&self, other: &dyn CustomConst) -> bool {
544        crate::ops::constant::downcast_equal_consts(self, other)
545    }
546
547    fn get_type(&self) -> Type {
548        self.typ.clone()
549    }
550
551    fn update_extensions(
552        &mut self,
553        extensions: &WeakExtensionRegistry,
554    ) -> Result<(), ExtensionResolutionError> {
555        resolve_type_extensions(&mut self.typ, extensions)
556    }
557
558    fn validate(&self) -> Result<(), CustomCheckFailure> {
559        if self.symbol.is_empty() {
560            Err(CustomCheckFailure::Message(
561                "External symbol name is empty.".into(),
562            ))
563        } else {
564            Ok(())
565        }
566    }
567}
568
569/// Logic extension operation definitions.
570#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, EnumIter, IntoStaticStr, EnumString)]
571#[allow(missing_docs)]
572#[non_exhaustive]
573pub enum TupleOpDef {
574    MakeTuple,
575    UnpackTuple,
576}
577
578impl ConstFold for TupleOpDef {
579    fn fold(
580        &self,
581        _type_args: &[TypeArg],
582        consts: &[(crate::IncomingPort, Value)],
583    ) -> crate::extension::ConstFoldResult {
584        match self {
585            TupleOpDef::MakeTuple => {
586                fold_out_row([Value::tuple(sorted_consts(consts).into_iter().cloned())])
587            }
588            TupleOpDef::UnpackTuple => {
589                let c = &consts.first()?.1;
590                let Some(vs) = c.as_tuple() else {
591                    panic!("This op always takes a Tuple input.");
592                };
593                fold_out_row(vs.iter().cloned())
594            }
595        }
596    }
597}
598
599impl MakeOpDef for TupleOpDef {
600    fn opdef_id(&self) -> OpName {
601        <&'static str>::from(self).into()
602    }
603
604    fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
605        let rv = TypeRV::new_row_var_use(0, TypeBound::Any);
606        let tuple_type = TypeRV::new_tuple(vec![rv.clone()]);
607
608        let param = TypeParam::new_list(TypeBound::Any);
609        match self {
610            TupleOpDef::MakeTuple => {
611                PolyFuncTypeRV::new([param], FuncValueType::new(rv, tuple_type))
612            }
613            TupleOpDef::UnpackTuple => {
614                PolyFuncTypeRV::new([param], FuncValueType::new(tuple_type, rv))
615            }
616        }
617        .into()
618    }
619
620    fn description(&self) -> String {
621        match self {
622            TupleOpDef::MakeTuple => "MakeTuple operation",
623            TupleOpDef::UnpackTuple => "UnpackTuple operation",
624        }
625        .to_string()
626    }
627
628    fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
629        try_from_name(op_def.name(), op_def.extension_id())
630    }
631
632    fn extension(&self) -> ExtensionId {
633        PRELUDE_ID.to_owned()
634    }
635
636    fn extension_ref(&self) -> Weak<Extension> {
637        Arc::downgrade(&PRELUDE)
638    }
639
640    fn post_opdef(&self, def: &mut OpDef) {
641        def.set_constant_folder(*self);
642    }
643}
644/// An operation that packs all its inputs into a tuple.
645#[derive(Debug, Clone, Default, PartialEq, Eq)]
646#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
647#[non_exhaustive]
648pub struct MakeTuple(pub TypeRow);
649
650impl MakeTuple {
651    /// Create a new MakeTuple operation.
652    pub fn new(tys: TypeRow) -> Self {
653        Self(tys)
654    }
655}
656
657impl MakeExtensionOp for MakeTuple {
658    fn op_id(&self) -> OpName {
659        TupleOpDef::MakeTuple.opdef_id()
660    }
661
662    fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
663    where
664        Self: Sized,
665    {
666        let def = TupleOpDef::from_def(ext_op.def())?;
667        if def != TupleOpDef::MakeTuple {
668            return Err(OpLoadError::NotMember(ext_op.unqualified_id().to_string()))?;
669        }
670        let [TypeArg::Sequence { elems }] = ext_op.args() else {
671            return Err(SignatureError::InvalidTypeArgs)?;
672        };
673        let tys: Result<Vec<Type>, _> = elems
674            .iter()
675            .map(|a| match a {
676                TypeArg::Type { ty } => Ok(ty.clone()),
677                _ => Err(SignatureError::InvalidTypeArgs),
678            })
679            .collect();
680        Ok(Self(tys?.into()))
681    }
682
683    fn type_args(&self) -> Vec<TypeArg> {
684        vec![TypeArg::Sequence {
685            elems: self
686                .0
687                .iter()
688                .map(|t| TypeArg::Type { ty: t.clone() })
689                .collect(),
690        }]
691    }
692}
693
694impl MakeRegisteredOp for MakeTuple {
695    fn extension_id(&self) -> ExtensionId {
696        PRELUDE_ID.to_owned()
697    }
698
699    fn extension_ref(&self) -> Weak<Extension> {
700        Arc::downgrade(&PRELUDE)
701    }
702}
703
704/// An operation that unpacks a tuple into its components.
705#[derive(Debug, Clone, Default, PartialEq, Eq)]
706#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
707#[non_exhaustive]
708pub struct UnpackTuple(pub TypeRow);
709
710impl UnpackTuple {
711    /// Create a new UnpackTuple operation.
712    pub fn new(tys: TypeRow) -> Self {
713        Self(tys)
714    }
715}
716
717impl MakeExtensionOp for UnpackTuple {
718    fn op_id(&self) -> OpName {
719        TupleOpDef::UnpackTuple.opdef_id()
720    }
721
722    fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
723    where
724        Self: Sized,
725    {
726        let def = TupleOpDef::from_def(ext_op.def())?;
727        if def != TupleOpDef::UnpackTuple {
728            return Err(OpLoadError::NotMember(ext_op.unqualified_id().to_string()))?;
729        }
730        let [TypeArg::Sequence { elems }] = ext_op.args() else {
731            return Err(SignatureError::InvalidTypeArgs)?;
732        };
733        let tys: Result<Vec<Type>, _> = elems
734            .iter()
735            .map(|a| match a {
736                TypeArg::Type { ty } => Ok(ty.clone()),
737                _ => Err(SignatureError::InvalidTypeArgs),
738            })
739            .collect();
740        Ok(Self(tys?.into()))
741    }
742
743    fn type_args(&self) -> Vec<TypeArg> {
744        vec![TypeArg::Sequence {
745            elems: self
746                .0
747                .iter()
748                .map(|t| TypeArg::Type { ty: t.clone() })
749                .collect(),
750        }]
751    }
752}
753
754impl MakeRegisteredOp for UnpackTuple {
755    fn extension_id(&self) -> ExtensionId {
756        PRELUDE_ID.to_owned()
757    }
758
759    fn extension_ref(&self) -> Weak<Extension> {
760        Arc::downgrade(&PRELUDE)
761    }
762}
763
764/// Name of the no-op operation.
765pub const NOOP_OP_ID: OpName = OpName::new_inline("Noop");
766
767#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
768/// A no-op operation definition.
769pub struct NoopDef;
770
771impl std::str::FromStr for NoopDef {
772    type Err = ();
773
774    fn from_str(s: &str) -> Result<Self, Self::Err> {
775        if s == NoopDef.op_id() {
776            Ok(Self)
777        } else {
778            Err(())
779        }
780    }
781}
782
783impl MakeOpDef for NoopDef {
784    fn opdef_id(&self) -> OpName {
785        NOOP_OP_ID
786    }
787
788    fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
789        let tv = Type::new_var_use(0, TypeBound::Any);
790        PolyFuncType::new([TypeBound::Any.into()], Signature::new_endo(tv)).into()
791    }
792
793    fn description(&self) -> String {
794        "Noop gate".to_string()
795    }
796
797    fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
798        try_from_name(op_def.name(), op_def.extension_id())
799    }
800
801    fn extension(&self) -> ExtensionId {
802        PRELUDE_ID.to_owned()
803    }
804
805    fn extension_ref(&self) -> Weak<Extension> {
806        Arc::downgrade(&PRELUDE)
807    }
808
809    fn post_opdef(&self, def: &mut OpDef) {
810        def.set_constant_folder(*self);
811    }
812}
813
814impl ConstFold for NoopDef {
815    fn fold(
816        &self,
817        _type_args: &[TypeArg],
818        consts: &[(crate::IncomingPort, Value)],
819    ) -> crate::extension::ConstFoldResult {
820        fold_out_row([consts.first()?.1.clone()])
821    }
822}
823
824/// A no-op operation.
825#[derive(Debug, Clone, PartialEq, Eq)]
826#[non_exhaustive]
827#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
828pub struct Noop(pub Type);
829
830impl Noop {
831    /// Create a new Noop operation.
832    pub fn new(ty: Type) -> Self {
833        Self(ty)
834    }
835}
836
837impl Default for Noop {
838    fn default() -> Self {
839        Self(Type::UNIT)
840    }
841}
842
843impl MakeExtensionOp for Noop {
844    fn op_id(&self) -> OpName {
845        NoopDef.op_id()
846    }
847
848    fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
849    where
850        Self: Sized,
851    {
852        let _def = NoopDef::from_def(ext_op.def())?;
853        let [TypeArg::Type { ty }] = ext_op.args() else {
854            return Err(SignatureError::InvalidTypeArgs)?;
855        };
856        Ok(Self(ty.clone()))
857    }
858
859    fn type_args(&self) -> Vec<TypeArg> {
860        vec![TypeArg::Type { ty: self.0.clone() }]
861    }
862}
863
864impl MakeRegisteredOp for Noop {
865    fn extension_id(&self) -> ExtensionId {
866        PRELUDE_ID.to_owned()
867    }
868
869    fn extension_ref(&self) -> Weak<Extension> {
870        Arc::downgrade(&PRELUDE)
871    }
872}
873
874#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
875/// A barrier operation definition.
876pub struct BarrierDef;
877
878/// Name of the barrier operation.
879pub const BARRIER_OP_ID: OpName = OpName::new_inline("Barrier");
880
881impl std::str::FromStr for BarrierDef {
882    type Err = ();
883
884    fn from_str(s: &str) -> Result<Self, Self::Err> {
885        if s == BarrierDef.op_id() {
886            Ok(Self)
887        } else {
888            Err(())
889        }
890    }
891}
892
893impl MakeOpDef for BarrierDef {
894    fn opdef_id(&self) -> OpName {
895        BARRIER_OP_ID
896    }
897
898    fn init_signature(&self, _extension_ref: &Weak<Extension>) -> SignatureFunc {
899        PolyFuncTypeRV::new(
900            vec![TypeParam::new_list(TypeBound::Any)],
901            FuncValueType::new_endo(TypeRV::new_row_var_use(0, TypeBound::Any)),
902        )
903        .into()
904    }
905
906    fn description(&self) -> String {
907        "Add a barrier to a row of values".to_string()
908    }
909
910    fn from_def(op_def: &OpDef) -> Result<Self, OpLoadError> {
911        try_from_name(op_def.name(), op_def.extension_id())
912    }
913
914    fn extension(&self) -> ExtensionId {
915        PRELUDE_ID.to_owned()
916    }
917
918    fn extension_ref(&self) -> Weak<Extension> {
919        Arc::downgrade(&PRELUDE)
920    }
921}
922
923/// A barrier across a row of values. This operation has no effect on the values,
924/// except to enforce some ordering between operations before and after the barrier.
925#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
926#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
927#[non_exhaustive]
928pub struct Barrier {
929    /// The types of the edges
930    pub type_row: TypeRow,
931}
932
933impl Barrier {
934    /// Create a new Barrier operation over the specified row.
935    pub fn new(type_row: impl Into<TypeRow>) -> Self {
936        Self {
937            type_row: type_row.into(),
938        }
939    }
940}
941
942impl NamedOp for Barrier {
943    fn name(&self) -> OpName {
944        BarrierDef.op_id()
945    }
946}
947
948impl MakeExtensionOp for Barrier {
949    fn op_id(&self) -> OpName {
950        BarrierDef.op_id()
951    }
952
953    fn from_extension_op(ext_op: &crate::ops::ExtensionOp) -> Result<Self, OpLoadError>
954    where
955        Self: Sized,
956    {
957        let _def = BarrierDef::from_def(ext_op.def())?;
958
959        let [TypeArg::Sequence { elems }] = ext_op.args() else {
960            return Err(SignatureError::InvalidTypeArgs)?;
961        };
962        let tys: Result<Vec<Type>, _> = elems
963            .iter()
964            .map(|a| match a {
965                TypeArg::Type { ty } => Ok(ty.clone()),
966                _ => Err(SignatureError::InvalidTypeArgs),
967            })
968            .collect();
969        Ok(Self {
970            type_row: tys?.into(),
971        })
972    }
973
974    fn type_args(&self) -> Vec<TypeArg> {
975        vec![TypeArg::Sequence {
976            elems: self
977                .type_row
978                .iter()
979                .map(|t| TypeArg::Type { ty: t.clone() })
980                .collect(),
981        }]
982    }
983}
984
985impl MakeRegisteredOp for Barrier {
986    fn extension_id(&self) -> ExtensionId {
987        PRELUDE_ID.to_owned()
988    }
989
990    fn extension_ref(&self) -> Weak<Extension> {
991        Arc::downgrade(&PRELUDE)
992    }
993}
994
995#[cfg(test)]
996mod test {
997    use crate::builder::inout_sig;
998    use crate::std_extensions::arithmetic::float_types::{float64_type, ConstF64};
999    use crate::{
1000        builder::{endo_sig, DFGBuilder, Dataflow, DataflowHugr},
1001        utils::test_quantum_extension::cx_gate,
1002        Hugr, Wire,
1003    };
1004
1005    use super::*;
1006    use crate::{
1007        ops::{OpTrait, OpType},
1008        type_row,
1009    };
1010
1011    #[test]
1012    fn test_make_tuple() {
1013        let op = MakeTuple::new(type_row![Type::UNIT]);
1014        let optype: OpType = op.clone().into();
1015        assert_eq!(
1016            optype.dataflow_signature().unwrap().io(),
1017            (
1018                &type_row![Type::UNIT],
1019                &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
1020            )
1021        );
1022
1023        let new_op = MakeTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1024        assert_eq!(new_op, op);
1025    }
1026
1027    #[test]
1028    fn test_unmake_tuple() {
1029        let op = UnpackTuple::new(type_row![Type::UNIT]);
1030        let optype: OpType = op.clone().into();
1031        assert_eq!(
1032            optype.dataflow_signature().unwrap().io(),
1033            (
1034                &vec![Type::new_tuple(type_row![Type::UNIT])].into(),
1035                &type_row![Type::UNIT],
1036            )
1037        );
1038
1039        let new_op = UnpackTuple::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1040        assert_eq!(new_op, op);
1041    }
1042
1043    #[test]
1044    fn test_noop() {
1045        let op = Noop::new(Type::UNIT);
1046        let optype: OpType = op.clone().into();
1047        assert_eq!(
1048            optype.dataflow_signature().unwrap().io(),
1049            (&type_row![Type::UNIT], &type_row![Type::UNIT])
1050        );
1051
1052        let new_op = Noop::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1053        assert_eq!(new_op, op);
1054    }
1055
1056    #[test]
1057    fn test_lift() {
1058        let op = Barrier::new(type_row![Type::UNIT]);
1059        let optype: OpType = op.clone().into();
1060        assert_eq!(
1061            optype.dataflow_signature().unwrap().as_ref(),
1062            &Signature::new_endo(type_row![Type::UNIT])
1063        );
1064
1065        let new_op = Barrier::from_extension_op(optype.as_extension_op().unwrap()).unwrap();
1066        assert_eq!(new_op, op);
1067    }
1068
1069    #[test]
1070    fn test_option() {
1071        let typ: Type = option_type(bool_t()).into();
1072        let const_val1 = const_some(Value::true_val());
1073        let const_val2 = const_none(bool_t());
1074
1075        let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1076
1077        let some = b.add_load_value(const_val1);
1078        let none = b.add_load_value(const_val2);
1079
1080        b.finish_hugr_with_outputs([some, none]).unwrap();
1081    }
1082
1083    #[test]
1084    fn test_result() {
1085        let typ: Type = either_type(bool_t(), float64_type()).into();
1086        let const_bool = const_left(Value::true_val(), float64_type());
1087        let const_float = const_right(bool_t(), ConstF64::new(0.5).into());
1088
1089        let mut b = DFGBuilder::new(inout_sig(type_row![], vec![typ.clone(), typ])).unwrap();
1090
1091        let bool = b.add_load_value(const_bool);
1092        let float = b.add_load_value(const_float);
1093
1094        b.finish_hugr_with_outputs([bool, float]).unwrap();
1095    }
1096
1097    #[test]
1098    /// test the prelude error type and panic op.
1099    fn test_error_type() {
1100        let ext_def = PRELUDE
1101            .get_type(&ERROR_TYPE_NAME)
1102            .unwrap()
1103            .instantiate([])
1104            .unwrap();
1105
1106        let ext_type = Type::new_extension(ext_def);
1107        assert_eq!(ext_type, error_type());
1108
1109        let error_val = ConstError::new(2, "my message");
1110
1111        assert_eq!(error_val.name(), "ConstError(2, \"my message\")");
1112
1113        assert!(error_val.validate().is_ok());
1114
1115        assert!(error_val.equal_consts(&ConstError::new(2, "my message")));
1116        assert!(!error_val.equal_consts(&ConstError::new(3, "my message")));
1117
1118        let mut b = DFGBuilder::new(endo_sig(type_row![])).unwrap();
1119
1120        let err = b.add_load_value(error_val);
1121
1122        const TYPE_ARG_NONE: TypeArg = TypeArg::Sequence { elems: vec![] };
1123        let op = PRELUDE
1124            .instantiate_extension_op(&EXIT_OP_ID, [TYPE_ARG_NONE, TYPE_ARG_NONE])
1125            .unwrap();
1126
1127        b.add_dataflow_op(op, [err]).unwrap();
1128
1129        b.finish_hugr_with_outputs([]).unwrap();
1130    }
1131
1132    #[test]
1133    /// test the panic operation with input and output wires
1134    fn test_panic_with_io() {
1135        let error_val = ConstError::new(42, "PANIC");
1136        let type_arg_q: TypeArg = TypeArg::Type { ty: qb_t() };
1137        let type_arg_2q: TypeArg = TypeArg::Sequence {
1138            elems: vec![type_arg_q.clone(), type_arg_q],
1139        };
1140        let panic_op = PRELUDE
1141            .instantiate_extension_op(&PANIC_OP_ID, [type_arg_2q.clone(), type_arg_2q.clone()])
1142            .unwrap();
1143
1144        let mut b = DFGBuilder::new(endo_sig(vec![qb_t(), qb_t()])).unwrap();
1145        let [q0, q1] = b.input_wires_arr();
1146        let [q0, q1] = b
1147            .add_dataflow_op(cx_gate(), [q0, q1])
1148            .unwrap()
1149            .outputs_arr();
1150        let err = b.add_load_value(error_val);
1151        let [q0, q1] = b
1152            .add_dataflow_op(panic_op, [err, q0, q1])
1153            .unwrap()
1154            .outputs_arr();
1155        b.finish_hugr_with_outputs([q0, q1]).unwrap();
1156    }
1157
1158    #[test]
1159    /// Test string type.
1160    fn test_string_type() {
1161        let string_custom_type: CustomType = PRELUDE
1162            .get_type(&STRING_TYPE_NAME)
1163            .unwrap()
1164            .instantiate([])
1165            .unwrap();
1166        let string_ty: Type = Type::new_extension(string_custom_type);
1167        assert_eq!(string_ty, string_type());
1168        let string_const: ConstString = ConstString::new("Lorem ipsum".into());
1169        assert_eq!(string_const.name(), "ConstString(\"Lorem ipsum\")");
1170        assert!(string_const.validate().is_ok());
1171        assert!(string_const.equal_consts(&ConstString::new("Lorem ipsum".into())));
1172        assert!(!string_const.equal_consts(&ConstString::new("Lorem ispum".into())));
1173    }
1174
1175    #[test]
1176    /// Test print operation
1177    fn test_print() {
1178        let mut b: DFGBuilder<Hugr> = DFGBuilder::new(endo_sig(vec![])).unwrap();
1179        let greeting: ConstString = ConstString::new("Hello, world!".into());
1180        let greeting_out: Wire = b.add_load_value(greeting);
1181        let print_op = PRELUDE.instantiate_extension_op(&PRINT_OP_ID, []).unwrap();
1182        b.add_dataflow_op(print_op, [greeting_out]).unwrap();
1183        b.finish_hugr_with_outputs([]).unwrap();
1184    }
1185
1186    #[test]
1187    fn test_external_symbol() {
1188        let subject = ConstExternalSymbol::new("foo", Type::UNIT, false);
1189        assert_eq!(subject.get_type(), Type::UNIT);
1190        assert_eq!(subject.name(), "@foo");
1191        assert!(subject.validate().is_ok());
1192        assert!(subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, false)));
1193        assert!(!subject.equal_consts(&ConstExternalSymbol::new("bar", Type::UNIT, false)));
1194        assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", string_type(), false)));
1195        assert!(!subject.equal_consts(&ConstExternalSymbol::new("foo", Type::UNIT, true)));
1196
1197        assert!(ConstExternalSymbol::new("", Type::UNIT, true)
1198            .validate()
1199            .is_err())
1200    }
1201}