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