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