2.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
}

2.31.1. Function Annotations

2.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).

2.31.1.2. Visibility

[private]

Makes a function private to the current module. Equivalent to the private keyword before def.

2.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.

2.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]

Warns if the return value of the function is discarded:

[nodiscard]
def compute : int {
    return 42
}

compute()       // warning: 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.

[skip_lock_check]

Skips array/table lock safety checks inside 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.

2.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).

2.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.

2.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:

[tag_function(my_tag)]
def tagged_func {
    pass
}

2.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.

2.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).

[skip_field_lock_check]

Skips field-level lock checking on array/table fields of this structure.

[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.

2.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).

2.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]
}

2.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 appear before the field name in the @ metadata syntax:

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.