vize_l3 0.608.0

L3 - the Davinci reactivity IR (codename Impeto): flat scheduled ops with explicit state and effect edges
Documentation
#![expect(clippy::indexing_slicing, reason = "tests assert by panicking")]
use vize_l0::{Allocator, Span, cstr};
use vize_l3::op::{Op, OpId, OpKind, Phase, Program, Region, RegionId};
use vize_l3::operand::{Operand, OperandRole as Role, OperandValue, ValueKind};
use vize_l3::verify::{ViolationCode, verify};

fn program(arena: &Allocator) -> Program<'_> {
    let mut program = Program::new(arena, Phase::Built);
    program.push_region(Region::root(Span::new(0, 100)));
    for (id, kind, span) in [
        (0, OpKind::If, Span::new(0, 100)),
        (1, OpKind::InsertNode, Span::new(10, 90)),
        (2, OpKind::SetProp, Span::new(20, 30)),
    ] {
        program.push_op(Op::new(OpId::new(id), kind, RegionId::ROOT, span));
    }
    program.push_region(Region::child(
        RegionId::new(1),
        RegionId::ROOT,
        OpId::new(0),
        Span::new(40, 90),
    ));
    program
}

fn binding() -> Operand<'static> {
    Operand {
        op: OpId::new(2),
        role: Role::Value,
        target: Some(OpId::new(1)),
        region: None,
        name: None,
        value: OperandValue {
            native_handler: None,
            kind: ValueKind::Js,
            text: "value",
            qualifier: "",
            span: Span::new(21, 26),
        },
    }
}

fn rejects(operand: Operand<'_>, message: &str) {
    let arena = Allocator::default();
    let mut program = program(&arena);
    program.operands.push(operand);
    let violations = verify(&program);
    assert_eq!(violations.len(), 1, "{violations:?}");
    assert_eq!(violations[0].code, ViolationCode::Operand);
    assert_eq!(violations[0].span, operand.value.span);
    assert_eq!(
        violations[0].message,
        cstr!(
            "operand {} for {}: {message}",
            operand.role.as_str(),
            operand.op
        )
    );
}

#[test]
fn valid_binding_and_branch_references_are_accepted_in_every_phase() {
    let arena = Allocator::default();
    let mut program = program(&arena);
    program.operands.push(binding());
    program.operands.push(Operand {
        op: OpId::new(0),
        role: Role::Condition,
        target: None,
        region: Some(RegionId::new(1)),
        ..binding()
    });
    for phase in [Phase::Built, Phase::Partitioned, Phase::Scheduled] {
        program.phase = phase;
        assert_eq!(verify(&program), []);
    }
}

#[test]
fn operand_owners_targets_and_spans_must_resolve() {
    rejects(
        Operand {
            op: OpId::new(99),
            ..binding()
        },
        "owner does not resolve",
    );
    rejects(
        Operand {
            target: Some(OpId::new(99)),
            ..binding()
        },
        "target does not resolve",
    );
    for target in [0, 2] {
        rejects(
            Operand {
                target: Some(OpId::new(target)),
                ..binding()
            },
            "target is not a containing materialized operation in the same region",
        );
    }
    rejects(
        Operand {
            value: OperandValue {
                native_handler: None,
                span: Span::new(19, 26),
                ..binding().value
            },
            ..binding()
        },
        "value span escapes owner",
    );
    for value in [
        OperandValue {
            span: Span::new(26, 21),
            ..binding().value
        },
        OperandValue {
            kind: ValueKind::Absent,
            ..binding().value
        },
        OperandValue {
            kind: ValueKind::Opaque,
            ..binding().value
        },
        OperandValue {
            kind: ValueKind::Foreign,
            ..binding().value
        },
        OperandValue {
            qualifier: "unexpected",
            ..binding().value
        },
    ] {
        rejects(Operand { value, ..binding() }, "malformed value");
    }
}

#[test]
fn attributes_and_conditions_enforce_their_role_contracts() {
    rejects(
        Operand {
            name: Some("id"),
            ..binding()
        },
        "attribute name must occur exactly on attribute roles",
    );
    rejects(
        Operand {
            role: Role::Attribute,
            ..binding()
        },
        "attribute name must occur exactly on attribute roles",
    );
    rejects(
        Operand {
            region: Some(RegionId::new(1)),
            ..binding()
        },
        "only condition operands may reference a branch",
    );
    let condition = Operand {
        op: OpId::new(0),
        role: Role::Condition,
        target: None,
        region: Some(RegionId::new(1)),
        ..binding()
    };
    for region in [None, Some(RegionId::new(99))] {
        rejects(
            Operand {
                region,
                ..condition
            },
            "condition branch does not resolve",
        );
    }
    rejects(
        Operand {
            op: OpId::new(2),
            ..condition
        },
        "condition branch must be owned by its if operation",
    );
    rejects(
        Operand {
            region: Some(RegionId::ROOT),
            ..condition
        },
        "condition branch must be owned by its if operation",
    );
}

#[test]
fn every_role_enforces_its_target_policy_in_every_phase() {
    for role in Role::ALL {
        for present in [false, true] {
            let expected = match role {
                Role::BindingKind
                | Role::Value
                | Role::Modifier
                | Role::ModelRead
                | Role::ModelWrite
                | Role::ModelAttribute
                | Role::Params => present,
                Role::Tag | Role::Name => true,
                _ => !present,
            };
            let arena = Allocator::default();
            let mut program = program(&arena);
            let condition = role == Role::Condition;
            program.operands.push(Operand {
                op: if condition {
                    OpId::new(0)
                } else {
                    OpId::new(2)
                },
                role,
                target: present.then_some(OpId::new(1)),
                region: condition.then_some(RegionId::new(1)),
                name: matches!(role, Role::Attribute | Role::ModelAttribute).then_some("id"),
                ..binding()
            });
            for phase in [Phase::Built, Phase::Partitioned, Phase::Scheduled] {
                program.phase = phase;
                let violations = verify(&program);
                if expected {
                    assert_eq!(
                        violations,
                        [],
                        "{role:?}/{present}/{phase:?}: {violations:?}"
                    );
                } else {
                    assert_eq!(violations.len(), 1, "{violations:?}");
                    assert_eq!(violations[0].code, ViolationCode::Operand);
                    assert_eq!(
                        violations[0].message,
                        cstr!(
                            "operand {} for {}: target presence does not match operand role",
                            role.as_str(),
                            program.operands[0].op
                        )
                    );
                }
            }
        }
    }
}