Worked Examples

These examples show how source code maps to the IR. Typed-id values like BindingId, VariantIdx, FieldIdx, MethodIdx, and the target field on Reference are populated by ResolveReferencesPass. Pre-pass (raw lowering output), they carry 0 / Unresolved placeholders.

Simple Struct

FormaLang source:

pub struct User {
    name: String,
    age: I32
}

IR structure:

IrModule
+-- structs[0]: IrStruct
    +-- name: "User"
    +-- visibility: Public
    +-- traits: []
    +-- fields:
    |   +-- [0] IrField
    |   |   +-- name: "name"
    |   |   +-- ty: Primitive(String)
    |   |   +-- mutable: false
    |   |   +-- optional: false
    |   |   +-- default: None
    |   +-- [1] IrField
    |       +-- name: "age"
    |       +-- ty: Primitive(I32)
    |       +-- mutable: false
    |       +-- optional: false
    |       +-- default: None
    +-- generic_params: []

Enum with Variants

FormaLang source:

pub enum Status {
    active,
    inactive,
    pending(reason: String)
}

IR structure:

IrModule
+-- enums[0]: IrEnum
    +-- name: "Status"
    +-- visibility: Public
    +-- variants:
    |   +-- [0] IrEnumVariant
    |   |   +-- name: "active"
    |   |   +-- fields: []
    |   +-- [1] IrEnumVariant
    |   |   +-- name: "inactive"
    |   |   +-- fields: []
    |   +-- [2] IrEnumVariant
    |       +-- name: "pending"
    |       +-- fields:
    |           +-- [0] IrField
    |               +-- name: "reason"
    |               +-- ty: Primitive(String)
    +-- generic_params: []

Struct Implementing Trait

FormaLang source:

pub trait Named {
    name: String
}

pub struct User: Named {
    name: String,
    age: I32
}

IR structure:

IrModule
+-- traits[0]: IrTrait              // TraitId(0)
|   +-- name: "Named"
|   +-- visibility: Public
|   +-- composed_traits: []
|   +-- fields:
|   |   +-- [0] IrField
|   |       +-- name: "name"
|   |       +-- ty: Primitive(String)
|   +-- methods: []
|   +-- generic_params: []
|
+-- structs[0]: IrStruct            // StructId(0)
    +-- name: "User"
    +-- visibility: Public
    +-- traits: [TraitId(0)]        // <-- linked to Named trait
    +-- fields:
    |   +-- [0] IrField { name: "name", ty: Primitive(String), ... }
    |   +-- [1] IrField { name: "age", ty: Primitive(I32), ... }
    +-- generic_params: []

Generic Struct with Constraint

FormaLang source:

pub trait Container {
    items: [String]
}

pub struct Box<T: Container> {
    content: T,
    label: String?
}

IR structure:

IrModule
+-- traits[0]: IrTrait              // TraitId(0)
|   +-- name: "Container"
|   +-- fields:
|       +-- [0] IrField
|           +-- name: "items"
|           +-- ty: Array(Box::new(Primitive(String)))
|
+-- structs[0]: IrStruct            // StructId(0)
    +-- name: "Box"
    +-- visibility: Public
    +-- traits: []
    +-- fields:
    |   +-- [0] IrField
    |   |   +-- name: "content"
    |   |   +-- ty: TypeParam("T")  // Unresolved in definition
    |   |   +-- optional: false
    |   +-- [1] IrField
    |       +-- name: "label"
    |       +-- ty: Optional(Box::new(Primitive(String)))
    |       +-- optional: true
    +-- generic_params:
        +-- [0] IrGenericParam
            +-- name: "T"
            +-- constraints: [TraitId(0)]  // <-- must implement Container

Struct with Cross-References

FormaLang source:

enum Status { active, inactive }

struct Author {
    name: String
}

struct Book {
    title: String,
    author: Author,
    status: Status
}

IR structure:

IrModule
+-- enums[0]: IrEnum                // EnumId(0)
|   +-- name: "Status"
|   +-- variants: [active, inactive]
|
+-- structs[0]: IrStruct            // StructId(0)
|   +-- name: "Author"
|   +-- fields:
|       +-- [0] IrField { name: "name", ty: Primitive(String) }
|
+-- structs[1]: IrStruct            // StructId(1)
    +-- name: "Book"
    +-- fields:
        +-- [0] IrField { name: "title", ty: Primitive(String) }
        +-- [1] IrField { name: "author", ty: Struct(StructId(0)) }  // linked!
        +-- [2] IrField { name: "status", ty: Enum(EnumId(0)) }      // linked!

Impl Block with Methods

FormaLang source:

pub struct Counter {
    count: I32
}

impl Counter {
    fn increment(self) -> I32 {
        self.count + 1
    }

    fn reset(mut self) -> I32 {
        0
    }
}

IR structure:

IrModule
+-- structs[0]: IrStruct            // StructId(0)
|   +-- name: "Counter"
|   +-- fields:
|       +-- [0] IrField { name: "count", ty: Primitive(I32) }
|
+-- impls[0]: IrImpl
    +-- target: ImplTarget::Struct(StructId(0))
    +-- functions:
        +-- [0] IrFunction
        |   +-- name: "increment"
        |   +-- params: [IrFunctionParam { name: "self", ty: None, convention: Let }]
        |   +-- return_type: Some(Primitive(I32))
        |   +-- body: Some(IrExpr::BinaryOp {
        |           left: IrExpr::Reference { path: ["self", "count"], ty: Primitive(I32) },
        |           op: Add,
        |           right: IrExpr::Literal { value: Number(NumberLiteral { value: NumberValue::Integer(1), .. }), ty: Primitive(I32) },
        |           ty: Primitive(I32)
        |       })
        +-- [1] IrFunction
            +-- name: "reset"
            +-- params: [IrFunctionParam { name: "self", ty: None, convention: Mut }]
            +-- return_type: Some(Primitive(I32))
            +-- body: Some(IrExpr::Literal { value: Number(NumberLiteral { value: NumberValue::Integer(0), .. }), ty: Primitive(I32) })

Match Expression

FormaLang source:

pub enum Option {
    none,
    some(value: I32)
}

pub fn describe(opt: Option) -> String {
    match opt {
        .none: "Nothing",
        .some(value): "Got value"
    }
}

IR structure:

IrModule
+-- enums[0]: IrEnum                // EnumId(0)
|   +-- name: "Option"
|   +-- variants:
|       +-- [0] IrEnumVariant { name: "none", fields: [] }
|       +-- [1] IrEnumVariant { name: "some", fields: [IrField { name: "value", ... }] }
|
+-- functions[0]: IrFunction
    +-- name: "describe"
    +-- params:
    |   +-- [0] IrFunctionParam { name: "opt", ty: Some(Enum(EnumId(0))), convention: Let }
    +-- return_type: Some(Primitive(String))
    +-- body: Some(IrExpr::Match {
            scrutinee: IrExpr::Reference {
                path: ["opt"],
                target: ReferenceTarget::Param(BindingId(0)),
                ty: Enum(EnumId(0))
            },
            arms: [
                IrMatchArm {
                    variant: "none",
                    variant_idx: VariantIdx(0),
                    is_wildcard: false,
                    bindings: [],
                    body: IrExpr::Literal { value: String("Nothing"), ty: Primitive(String) }
                },
                IrMatchArm {
                    variant: "some",
                    variant_idx: VariantIdx(1),
                    is_wildcard: false,
                    bindings: [("value", BindingId(1), Primitive(I32))],
                    body: IrExpr::Literal { value: String("Got value"), ty: Primitive(String) }
                }
            ],
            ty: Primitive(String)
        })

For Expression

FormaLang source:

pub fn tag_labels(tags: [String]) -> [String] {
    for tag in tags { tag }
}

IR structure:

IrModule
+-- functions[0]: IrFunction
    +-- name: "tag_labels"
    +-- params:
    |   +-- [0] IrFunctionParam { name: "tags", ty: Some(Array(Primitive(String))), convention: Let }
    +-- return_type: Some(Array(Primitive(String)))
    +-- body: Some(IrExpr::For {
            var: "tag",
            var_ty: Primitive(String),
            var_binding_id: BindingId(1),
            collection: IrExpr::Reference {
                path: ["tags"],
                target: ReferenceTarget::Param(BindingId(0)),
                ty: Array(Primitive(String))
            },
            body: IrExpr::LetRef {
                name: "tag",
                binding_id: BindingId(1),
                ty: Primitive(String)
            },
            ty: Array(Primitive(String))
        })