provekit_noirc_driver 1.0.0-beta.20-alpha.1

Noir compiler driver.
Documentation
//! Contains methods on the built-in `Type` type used for representing a type in the source program.

use crate::cmp::Eq;
use crate::option::Option;

/// Creates and returns an unbound type variable. This is a special kind of type internal
/// to type checking which will type check with any other type. When it is type checked
/// against another type it will also be set to that type. For example, if `a` is a type
/// variable and we have the type equality `(a, i32) = (u8, i32)`, the compiler will set
/// `a` equal to `u8`.
///
/// Unbound type variables will often be rendered as `_` while printing them. Bound type
/// variables will appear as the type they are bound to.
///
/// This can be used in conjunction with functions which internally perform type checks
/// such as [`Type::implements`] or [`Type::get_trait_impl`] to potentially grab some of the types used.
///
/// Note that calling [`Type::implements`] or [`Type::get_trait_impl`] on a type variable will always
/// fail.
///
/// Example:
///
/// ```noir
/// trait Serialize<let N: u32> {}
///
/// impl Serialize<1> for Field {}
///
/// impl<T, let N: u32, let M: u32> Serialize<N * M> for [T; N]
///     where T: Serialize<M> {}
///
/// impl<T, U, let N: u32, let M: u32> Serialize<N + M> for (T, U)
///     where T: Serialize<N>, U: Serialize<M> {}
///
/// fn fresh_variable_example() {
///     let typevar1 = std::meta::typ::fresh_type_variable();
///     let constraint = quote { Serialize<$typevar1> }.as_trait_constraint();
///     let field_type = quote { Field }.as_type();
///
///     // Search for a trait impl (binding typevar1 to 1 when the impl is found):
///     assert(field_type.implements(constraint));
///
///     // typevar1 should be bound to the "1" generic now:
///     assert_eq(typevar1.as_constant().unwrap(), 1);
///
///     // If we want to do the same with a different type, we need to
///     // create a new type variable now that `typevar1` is bound
///     let typevar2 = std::meta::typ::fresh_type_variable();
///     let constraint = quote { Serialize<$typevar2> }.as_trait_constraint();
///     let array_type = quote { [(Field, Field); 5] }.as_type();
///     assert(array_type.implements(constraint));
///
///     // Now typevar2 should be bound to the serialized pair size 2 times the array length 5
///     assert_eq(typevar2.as_constant().unwrap(), 10);
/// }
/// ```
#[builtin(fresh_type_variable)]
// docs:start:fresh_type_variable
pub comptime fn fresh_type_variable() -> Type {}
// docs:end:fresh_type_variable

impl Type {
    /// If this type is an array, return a pair of (element type, size type).
    ///
    /// Example:
    ///
    /// ```noir
    /// comptime {
    ///     let array_type = quote { [Field; 3] }.as_type();
    ///     let (field_type, three_type) = array_type.as_array().unwrap();
    ///
    ///     assert(field_type.is_field());
    ///     assert_eq(three_type.as_constant().unwrap(), 3);
    /// }
    /// ```
    #[builtin(type_as_array)]
    // docs:start:as_array
    pub comptime fn as_array(self) -> Option<(Type, Type)> {}
    // docs:end:as_array

    /// If this type is a constant integer (such as the `3` in the array type `[Field; 3]`),
    /// return the numeric constant.
    #[builtin(type_as_constant)]
    // docs:start:as_constant
    pub comptime fn as_constant(self) -> Option<u32> {}
    // docs:end:as_constant

    /// If this is an integer type, return a boolean which is `true`
    /// if the type is signed, as well as the number of bits of this integer type.
    #[builtin(type_as_integer)]
    // docs:start:as_integer
    pub comptime fn as_integer(self) -> Option<(bool, u8)> {}
    // docs:end:as_integer

    /// If this is a mutable reference type `&mut T`, returns the mutable type `T`.
    #[builtin(type_as_mutable_reference)]
    // docs:start:as_mutable_reference
    pub comptime fn as_mutable_reference(self) -> Option<Type> {}
    // docs:end:as_mutable_reference

    /// If this is a vector type, return the element type of the vector.
    #[builtin(type_as_vector)]
    // docs:start:as_vector
    pub comptime fn as_vector(self) -> Option<Type> {}
    // docs:end:as_vector

    /// If this is a vector type, return the element type of the vector.
    #[builtin(type_as_vector)]
    #[deprecated("This method has been renamed to `as_vector`")]
    pub comptime fn as_slice(self) -> Option<Type> {}

    /// If this is a `str<N>` type, returns the length `N` as a type.
    #[builtin(type_as_str)]
    // docs:start:as_str
    pub comptime fn as_str(self) -> Option<Type> {}
    // docs:end:as_str

    #[deprecated("This method has been renamed to `as_data_type`")]
    pub comptime fn as_struct(self) -> Option<(TypeDefinition, [Type])> {
        self.as_data_type()
    }

    /// If this is a struct or enum type, returns the type in addition to any generic arguments on this type.
    #[builtin(type_as_data_type)]
    // docs:start:as_data_type
    pub comptime fn as_data_type(self) -> Option<(TypeDefinition, [Type])> {}
    // docs:end:as_data_type

    /// If this is a tuple type, returns each element type of the tuple.
    #[builtin(type_as_tuple)]
    // docs:start:as_tuple
    pub comptime fn as_tuple(self) -> Option<[Type]> {}
    // docs:end:as_tuple

    /// Retrieves the trait implementation that implements the given
    /// trait constraint for this type. If the trait constraint is not
    /// found, `None` is returned. Note that since the concrete trait implementation
    /// for a trait constraint specified from a `where` clause is unknown,
    /// this function will return `None` in these cases. If you only want to know
    /// whether a type implements a trait, use `implements` instead.
    ///
    /// Example:
    ///
    /// ```rust
    /// comptime {
    ///     let field_type = quote { Field }.as_type();
    ///     let default = quote { Default }.as_trait_constraint();
    ///
    ///     let the_impl: TraitImpl = field_type.get_trait_impl(default).unwrap();
    ///     assert(the_impl.methods().len(), 1);
    /// }
    /// ```
    #[builtin(type_get_trait_impl)]
    // docs:start:get_trait_impl
    pub comptime fn get_trait_impl(self, constraint: TraitConstraint) -> Option<TraitImpl> {}
    // docs:end:get_trait_impl

    /// Returns `true` if this type implements the given trait. Note that unlike
    /// `get_trait_impl` this will also return true for any `where` constraints
    /// in scope.
    ///
    /// Example:
    ///
    /// ```rust
    /// fn foo<T>() where T: Default {
    ///     comptime {
    ///         let field_type = quote { Field }.as_type();
    ///         let default = quote { Default }.as_trait_constraint();
    ///         assert(field_type.implements(default));
    ///
    ///         let t = quote { T }.as_type();
    ///         assert(t.implements(default));
    ///     }
    /// }
    /// ```
    #[builtin(type_implements)]
    // docs:start:implements
    pub comptime fn implements(self, constraint: TraitConstraint) -> bool {}
    // docs:end:implements

    /// Returns `true` if this type is `bool`.
    #[builtin(type_is_bool)]
    // docs:start:is_bool
    pub comptime fn is_bool(self) -> bool {}
    // docs:end:is_bool

    /// Returns `true` if this type is `Field`.
    #[builtin(type_is_field)]
    // docs:start:is_field
    pub comptime fn is_field(self) -> bool {}
    // docs:end:is_field

    /// Returns `true` if this type is the unit `()` type.
    #[builtin(type_is_unit)]
    // docs:start:is_unit
    pub comptime fn is_unit(self) -> bool {}
    // docs:end:is_unit
}

impl Eq for Type {
    /// Note that this is syntactic equality, this is not the same as whether two types will type check
    /// to be the same type. Unless type inference or generics are being used however, users should not
    /// typically have to worry about this distinction.
    comptime fn eq(self, other: Self) -> bool {
        type_eq(self, other)
    }
}

impl crate::hash::Hash for Type {
    comptime fn hash<H>(self, state: &mut H)
    where
        H: crate::hash::Hasher,
    {
        state.write(type_hash(self))
    }
}

#[builtin(type_eq)]
comptime fn type_eq(_first: Type, _second: Type) -> bool {}

#[builtin(type_hash)]
comptime fn type_hash(_typ: Type) -> Field {}