3.31. Annotations

Annotations are metadata decorators attached to functions, structures, classes, enumerations, and variables. They control compiler behavior — export, initialization, safety, optimization, and macro registration.

An annotation is written in square brackets before the declaration it applies to:

[export]
def main {
    print("hello\n")
}

Multiple annotations can be combined with commas:

[export, no_aot]
def main {
    print("hello\n")
}

Some annotations accept arguments:

[init(tag="db")]
def init_database {
    pass
}

[unused_argument(x, y)]
def foo(x, y : int) {
    pass
}

3.31.1. Function Annotations

3.31.1.1. Lifecycle

[export]

Marks a function as callable from the host application. The host invokes exported functions by name through the context API:

[export]
def main {
    print("hello\n")
}
[init]

Marks a function to run automatically during context initialization. The function must take no arguments and return void:

[init]
def setup {
    pass
}

Ordering can be controlled with attributes:

  • tag — defines a named initialization pass

  • before — runs before the named pass

  • after — runs after the named pass

All ordering attributes imply late initialization:

[init(tag="db")]
def init_database {
    pass
}

[init(after="db")]
def init_cache {
    pass
}
[finalize]

Marks a function to run automatically during context shutdown. Same constraints as [init] — no arguments, no return value:

[finalize]
def cleanup {
    pass
}

Supports a late attribute for ordering.

[run]

Marks a function to run at compile time:

[run]
def compile_time_check {
    print("compiling...\n")
}

Disabled by the disable_run option (see Options).

(see Program Structure for the full initialization lifecycle).

3.31.1.2. Visibility

Visibility is controlled with the private prefix keyword, not an annotation. Place private after def to make a function private to the current module:

def private helper {
    pass
}

There is no [private] annotation form.

3.31.1.3. Safety

[unsafe_deref]

Marks a function as allowing unsafe dereferences inside its body:

[unsafe_deref]
def read_ptr(p : int?) {
    return *p
}
[unsafe_operation]

Marks a function as an unsafe operation. Calling it requires an unsafe block:

[unsafe_operation]
def dangerous_thing {
    pass
}

unsafe {
    dangerous_thing()
}
[unsafe_outside_of_for]

Marks a function as unsafe when called outside of a for loop body.

3.31.1.4. Lint Control

[unused_argument]

Suppresses “unused argument” warnings for specific arguments:

[unused_argument(x)]
def handler(x : int) {
    pass
}

Multiple arguments can be listed: [unused_argument(x, y)].

[nodiscard]

Errors if the return value of the function is discarded:

[nodiscard]
def compute : int {
    return 42
}

compute()       // error: return value discarded
[deprecated]

Marks a function as deprecated. Produces a compile-time warning when called:

[deprecated(message="use new_func instead")]
def old_func {
    pass
}
[no_lint]

Disables all lint checks for this function.

[sideeffects]

Declares that the function has side effects, even if the compiler cannot detect any. Prevents the optimizer from removing calls to this function.

3.31.1.5. Generics and Contracts

[generic]

Marks a function as generic (a template that is instantiated for each unique set of argument types):

[generic]
def add(a, b : auto) {
    return a + b
}

(see Generic Programming).

[expect_ref]

Specialization contract: requires named arguments to be references:

[expect_ref(arr)]
def process(var arr : auto) {
    pass
}
[expect_dim]

Specialization contract: requires named arguments to be fixed-size arrays.

[expect_any_vector]

Specialization contract: requires named arguments to be vector template types.

[local_only]

Verifies that specific arguments are passed as local constructors. The argument value indicates the expected state — true means the argument must be a literal constructor, false means it must not be:

[local_only(data=true)]
def process(data : Foo) {
    pass
}

Additional contract annotations are available in daslib/contracts (see Contract Annotations (daslib) below).

3.31.1.6. Optimization and AOT

[no_aot]

Disables AOT (ahead-of-time) compilation for this function.

[no_jit]

Disables JIT compilation for this function.

[jit]

Requests JIT compilation for this function.

[hybrid]

Marks a function as an AOT hybrid — it can call interpreted code from AOT context.

[alias_cmres]

Allows aliasing of the copy-on-move return value.

[never_alias_cmres]

Prevents aliasing of the copy-on-move return value.

[pinvoke]

Marks a function for platform invoke (external function call).

[type_function]

Registers the function as usable in type expressions.

3.31.1.7. Macros

[_macro]

Marks a function as macro initialization code (runs during macro compilation pass).

[macro_function]

Marks a function as existing only in the macro context — excluded from the regular program.

[macro]

Defined in daslib/ast_boost. Like [_macro] but wraps the function body in a module-ready check. Requires require daslib/ast_boost:

require daslib/ast_boost

[macro]
def setup_macros {
    print("registering macros\n")
}
[tag_function]

Defined in daslib/ast_boost. Tags a function with string tags for retrieval via for_each_tag_function:

require daslib/ast_boost

[tag_function(my_tag)]
def tagged_func {
    pass
}

3.31.1.8. Markers and Hints

[hint]

A dummy annotation that carries key-value arguments for optimization hints. Does not change behavior by itself.

[marker]

A generic function marker annotation. Does not change behavior.

3.31.2. Structure and Class Annotations

[cpp_layout]

Uses C++ memory layout (matching C++ struct alignment rules):

[cpp_layout]
struct CppInterop {
    x : int
    y : float
}

Pass pod=false to allow non-POD layouts: [cpp_layout(pod=false)].

[safe_when_uninitialized]

Marks the struct as safe even when fields are uninitialized (zero-filled memory is a valid state):

[safe_when_uninitialized]
struct Vec2 {
    x : float
    y : float
}
[persistent]

Makes a structure persistent (survives context reset). All fields must be POD unless non_pod=true is specified:

[persistent]
struct Config {
    value : int
}
[no_default_initializer]

Suppresses generation of the default constructor for this structure.

[macro_interface]

Marks a structure as a macro interface (for the macro system).

[comment]

A dummy annotation for attaching comment metadata to a structure.

[tag_structure]

Defined in daslib/ast_boost. Tags a structure with string tags for later retrieval.

3.31.3. Macro Registration Annotations (daslib)

These annotations are defined in daslib/ast_boost and applied to class declarations that inherit from the appropriate AST base class. They auto-register the class as a macro during module compilation.

All accept an optional name argument. If omitted, the class name is used.

Annotation

Base class

Purpose

[function_macro]

AstFunctionAnnotation

Custom function decorator

[block_macro]

AstBlockAnnotation

Custom block decorator

[structure_macro]

AstStructureAnnotation

Custom struct/class decorator

[enumeration_macro]

AstEnumerationAnnotation

Custom enum decorator

[contract]

AstFunctionAnnotation

Specialization constraint

[reader_macro]

AstReaderMacro

Custom literal/expression reader

[comment_reader]

AstCommentReader

Custom comment reader

[call_macro]

AstCallMacro

Intercepts function-like calls

[typeinfo_macro]

AstTypeInfoMacro

Custom typeinfo(...) handler

[variant_macro]

AstVariantMacro

Custom variant type processing

[for_loop_macro]

AstForLoopMacro

Custom for-loop behavior

[capture_macro]

AstCaptureMacro

Custom closure capture handling

[type_macro]

AstTypeMacro

Custom type expression processing

[simulate_macro]

AstSimulateMacro

Custom simulation node generation

[infer_macro]

AstInferMacro

Runs during type inference

[dirty_infer_macro]

AstDirtyInferMacro

Runs during dirty inference passes

[optimization_macro]

AstOptimizationMacro

Runs during optimization

[lint_macro]

AstLintMacro

Runs during linting

[global_lint_macro]

AstGlobalLintMacro

Runs after all modules are compiled

Example:

require daslib/ast_boost

[function_macro(name="my_decorator")]
class MyDecorator : AstFunctionAnnotation {
    def override apply(var func : FunctionPtr; var group : ModuleGroup;
                       args : AnnotationArgumentList; var errors : das_string) : bool {
        print("decorating {func.name}\n")
        return true
    }
}

(see Macros for details on writing macros).

3.31.4. Contract Annotations (daslib)

These annotations are defined in daslib/contracts and used as specialization constraints on generic function arguments. Each accepts one or more argument names to constrain.

Requires require daslib/contracts.

Annotation

Constraint

[expect_any_array(arg)]

Argument must be a dynamic array

[expect_any_enum(arg)]

Argument must be an enum

[expect_any_bitfield(arg)]

Argument must be a bitfield

[expect_any_vector_type(arg)]

Argument must be a vector template type

[expect_any_struct(arg)]

Argument must be a struct

[expect_any_numeric(arg)]

Argument must be a numeric type

[expect_any_workhorse(arg)]

Argument must be a “workhorse” type (int, float, etc.)

[expect_any_tuple(arg)]

Argument must be a tuple

[expect_any_variant(arg)]

Argument must be a variant

[expect_any_function(arg)]

Argument must be a function type

[expect_any_lambda(arg)]

Argument must be a lambda

[expect_ref(arg)]

Argument must be a reference

[expect_pointer(arg)]

Argument must be a pointer

[expect_class(arg)]

Argument must be a class pointer

[expect_value_handle(arg)]

Argument must be a value handle type

Example:

require daslib/contracts

[expect_any_array(arr)]
def first_element(arr : auto) {
    return arr[0]
}

3.31.5. Annotation Syntax Details

Annotations can be combined with logical operators for contract composition:

[expect_ref(a) && expect_dim(b)]
def process(var a : auto; b : auto) {
    pass
}

Negation is also supported:

[!expect_ref(a)]
def no_ref(a : auto) {
    pass
}

Annotations on struct/class fields use the @ metadata syntax and appear before the field declaration:

class Foo {
    @big
    @min = 13
    @max = 42
    value : int
}

These @ decorators attach metadata to the field. They are accessible via typeinfo and at compile time in macros.