Metaprogramming in Noir is built on three pillars:Documentation Index
Fetch the complete documentation index at: https://mintlify.com/noir-lang/noir/llms.txt
Use this file to discover all available pages before exploring further.
comptimecode — functions, globals, blocks, and loops that execute at compile time.- Quoting and unquoting — creating, manipulating, and splicing token streams (
Quotedvalues). - The
std::metaAPI — compiler-provided types and intrinsics that let you inspect and modify the program.
comptime functions that generate and insert code into the program.
comptime basics
Thecomptime keyword marks code as executing at compile time:
| Syntax | Meaning |
|---|---|
comptime fn | Function that runs only during compilation |
comptime global | Global variable evaluated at compile time (may be mutable) |
comptime let | Variable whose value is evaluated at compile time |
comptime { ... } | Block of statements executed at compile time |
comptime for | for loop executed at compile time |
comptime fn
Quoted, Type, FunctionDefinition, etc.
comptime global
Unlike runtime globals,comptime global values can be mutable:
comptime let
comptime blocks
Acomptime {} block runs its statements during compilation. The result is lowered to a runtime literal:
comptime for
Syntactic sugar forcomptime { for ... }. Runs a for loop at compile time:
Quote and unquote
AQuoted value is a token stream — a compile-time representation of source code. Create one with a quote { ... } expression:
Unquoting with $
The$ operator splices a variable’s value into a quoted token stream:
Quoted values:
$ with a backslash to prevent unquoting:
Quoted is internally a vector of tokens, not a string. Concatenation works like vector concatenation. foo$x with x = 3 gives [foo, 3], not [foo3]. Use format strings and .quoted_contents() if you need string semantics.$crate
When writing macros in a library, use$crate to refer to the crate the quote is in, ensuring it resolves correctly even when the macro is used from external crates:
Calling macros
Acomptime function that returns Quoted is a macro. Append ! to the function call to insert the token stream at the call site:
!, the function just returns the Quoted value for further manipulation.
Attributes
An attribute applies acomptime function to an item. The function is called with that item as its first argument:
#[derive]-like functionality works.
Attribute arguments
Pass additional arguments to an attribute:Attribute evaluation order
Within a module, attributes are evaluated top to bottom. Attributes in child modules are evaluated before those in parent modules. Sibling modules are evaluated in the order of theirmod declarations:
The std::meta API
Thestd::meta module provides compiler-backed types for inspecting and modifying the program. Key types include:
Quoted
Quoted
A token stream. Methods include:
.tokens()— iterate over individual tokens.quoted_contents()— convert a format string back toQuoted.as_type()— parse as a type in the current scope.as_trait_constraint()— parse as a trait constraint
Type
Type
Represents a Noir type at compile time.
fn implements(self, constraint: TraitConstraint) -> bool— check if this type implements a trait
Expr
Expr
A syntactically valid expression. Useful for recursing over the parse tree.
fn as_function_call(self) -> Option<(Expr, [Expr])>— if this is a function call, return(function, arguments)fn as_block(self) -> Option<[Expr]>— if this is a block, return the statements
FunctionDefinition
FunctionDefinition
Represents a function.
fn parameters(self) -> [(Quoted, Type)]— returns(name, type)pairs for each parameter
TypeDefinition
TypeDefinition
Represents a struct or enum definition.
fn as_type(self) -> Type— returns this as aTypefn generics(self) -> [Quoted]— returns names of each genericfn fields(self) -> [(Quoted, Type)]— returns name and type of each field
TraitConstraint
TraitConstraint
A trait constraint expression such as
From<Field>.#[use_callers_scope]
By default,Quoted::as_type and similar methods resolve in the attribute function’s scope. If you want them to resolve in the scope of the caller (the code being annotated), add #[use_callers_scope] to your attribute function:
Writing a derive macro
The full metaprogramming system enables derive-like functionality. From the user’s perspective:derive requires a comptime function that:
- Accepts the struct’s
TypeDefinition. - Iterates over trait names passed as arguments.
- Looks up a registered derive function for each trait.
- Calls it and collects the generated
Quotedimpls.
Quoted value is inserted at the top level, adding a new trait implementation to the program.
Counting fields with a derive attribute
A simple derive example that counts struct fields at compile time and generates afield_count method:
Foo::field_count() returns 2.