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