Contracts & Verification
AILANG supports design-by-contract programming through requires and ensures clauses. Contracts make function invariants explicit and machine-checkable.
This feature implements techniques from the ARC (Automated Reasoning Checks) system developed by AWS:
Bayless et al., "A Neurosymbolic Approach to Natural Language Formalization and Verification" (2025) PDF
ARC demonstrates that formal verification combined with AI code generation dramatically improves correctness. AILANG brings these techniques into the language itself.
Contract Syntax
Contracts appear after the effect annotation and before the function body:
export func safeDivide(dividend: int, divisor: int) -> int ! {}
requires { divisor != 0 } -- Precondition: checked at entry
ensures { result >= 0 } -- Postcondition: checked before return
{
dividend / divisor
}
Key Elements
| Clause | Purpose | When Checked |
|---|---|---|
requires { ... } | Precondition - what must be true when calling | Function entry |
ensures { ... } | Postcondition - what will be true when returning | Before return |
result | Special identifier for the return value | Only in ensures |
Multiple Predicates
Separate multiple predicates with commas:
export func clamp(value: int, min: int, max: int) -> int ! {}
requires { min <= max }
ensures { result >= min, result <= max }
{
if value < min then min
else if value > max then max
else value
}
Basic Example
This example demonstrates core contract patterns:
-- examples/runnable/contracts/basic.ail
-- Basic contract examples demonstrating requires/ensures syntax
-- M-VERIFY: Phase 0 - Contract parsing infrastructure
module examples/runnable/contracts/basic
-- Type definitions for examples
export type Status = OK | FAIL
-- Simple function with precondition
-- requires: x must be non-negative
export func absolute(x: int) -> int ! {}
requires { x >= 0 }
ensures { result >= 0 }
{
x
}
-- Function with multiple requires predicates
export func safeDivide(dividend: int, divisor: int) -> int ! {}
requires { divisor != 0 }
ensures { result >= 0 }
{
dividend / divisor
}
-- Function with both requires and ensures
export func increment(x: int, max: int) -> int ! {}
requires { x >= 0 }
ensures { result > x }
{
if x + 1 > max then max else x + 1
}
-- Function demonstrating 'result' in ensures
export func clamp(value: int, minVal: int, maxVal: int) -> int ! {}
requires { minVal <= maxVal }
ensures { result >= minVal }
{
if value < minVal then minVal
else if value > maxVal then maxVal
else value
}
-- Simple entry point for testing
export func main() -> int ! {}
{
let a = absolute(5);
let b = safeDivide(10, 2);
let c = increment(5, 100);
let d = clamp(150, 0, 100);
a + b + c + d
}
Run it:
ailang run --caps IO --entry main examples/runnable/contracts/basic.ail
# Output: 116
Policy Example: Park Admission
This example reproduces the park admission policy from the ARC paper, demonstrating how AILANG can express the same policy models with machine-checkable contracts.
-- examples/runnable/contracts/park.ail
-- Reproduces ARC paper park admission example in AILANG
-- From: Bayless et al., "A Neurosymbolic Approach to Natural Language Formalization and Verification" (AWS, 2025)
-- M-VERIFY: Showcase example demonstrating contract-based policy specification
module examples/runnable/contracts/park
-- Type vocabulary (matching ARC's datatypes/variables)
export type Season = LOW_SEASON | HIGH_SEASON
export type AgeClass = CHILD | ADULT | SENIOR
export type AdmissionDecision = ADMIT | DENY
-- Core policy function with contracts
-- ARC rule: "Seniors pay $5 in low season, $10 in high season"
-- ARC rule: "Children under 5 free in low season"
export func admissionFee(age: int, season: Season) -> int ! {}
requires { age >= 0 }
ensures { result >= 0 }
{
match season {
LOW_SEASON =>
if age < 5 then 0
else if age >= 65 then 5
else 15,
HIGH_SEASON =>
if age >= 65 then 10
else 20
}
}
-- Decision function: can visitor enter park given budget?
export func canEnterPark(age: int, season: Season, budget: int) -> AdmissionDecision ! {}
requires { age >= 0 }
{
let fee = admissionFee(age, season);
if budget >= fee then ADMIT else DENY
}
-- Age classification helper
export func classifyAge(age: int) -> AgeClass ! {}
requires { age >= 0 }
{
if age < 5 then CHILD
else if age >= 65 then SENIOR
else ADULT
}
-- Entry point for testing
export func main() -> int ! {}
{
-- Test cases from ARC paper scenarios
let seniorLow = admissionFee(70, LOW_SEASON); -- Expected: 5
let seniorHigh = admissionFee(70, HIGH_SEASON); -- Expected: 10
let childLow = admissionFee(3, LOW_SEASON); -- Expected: 0
let adultHigh = admissionFee(30, HIGH_SEASON); -- Expected: 20
-- Sum of all fees (5 + 10 + 0 + 20 = 35)
seniorLow + seniorHigh + childLow + adultHigh
}
Run it:
ailang run --caps IO --entry main examples/runnable/contracts/park.ail
# Output: 35 (= 5 + 10 + 0 + 20)
What This Demonstrates
The park example shows:
- Domain modeling with ADTs: Types like
Season,AgeClass, andAdmissionDecisioncapture the policy vocabulary - Business rules as contracts: "Seniors pay $5 in low season" becomes
ensures { result >= 0 } - Function composition:
canEnterParkbuilds onadmissionFeewith contracts propagating - Testable specifications: The
mainfunction exercises the policy with known test cases
Why Contracts Matter for AI
Contracts are particularly valuable for AI code generation:
| Benefit | Explanation |
|---|---|
| Specification surface | AI can read contracts to understand intent |
| Verification target | Generated code can be checked against contracts |
| Confidence scoring | Multiple AI-generated implementations can be compared for contract satisfaction |
| Audit trail | Contracts document what was specified vs. implemented |
The ARC Approach
The ARC paper demonstrates that:
- Having AI generate both contracts and code improves correctness
- Redundant generation (multiple samples) + verification catches bugs
- Formal specifications make AI reasoning auditable
AILANG implements this pattern natively: contracts are first-class syntax, not comments or annotations.
Runtime Contract Checking
Enable runtime contract verification with the --verify-contracts flag:
# Compile with contract checks enabled
ailang compile --verify-contracts examples/runnable/contracts/basic.ail -o output/
# Run with contracts (coming in v0.6.2)
ailang run --verify-contracts --caps IO --entry main examples/runnable/contracts/basic.ail
What Gets Generated
With --verify-contracts: Both documentation comments and panic checks:
func absolute_impl(x interface{}) interface{} {
// Requires: (x >= 0)
if !(GeInt(x, int64(0))).(bool) {
panic("contract violation: requires: (x >= 0) at basic.ail:13:12")
}
return x
}
func Absolute(x int64) int64 {
_result := absolute_impl(x).(int64)
// Ensures: (result >= 0)
if !(_result >= int64(0)) {
panic("contract violation: ensures: (result >= 0) at basic.ail:14:11")
}
return _result
}
Without --verify-contracts: Documentation comments only (no runtime overhead):
func absolute_impl(x interface{}) interface{} {
// Requires: (x >= 0)
return x
}
Contract Violation Messages
When a contract is violated at runtime, you get a clear panic message:
panic: contract violation: requires: (divisor != 0) at basic.ail:21:12
The message includes:
- Contract type (
requiresorensures) - Original predicate expression
- Source location (file:line:column)
Current Status
Phase 0 + 0.5 Complete (v0.6.2):
- ✅ Contract syntax (
requires/ensures) parses correctly - ✅ Contracts stored in Core AST (
core.DeclMeta.Contracts) - ✅ Runtime checks with
--verify-contractsflag - ✅ Precondition (
requires) checks at function entry - ✅ Postcondition (
ensures) checks before return - ✅
resultidentifier maps to return value in ensures
Future (Phase 1): SMT-based verification for provably correct code via ailang verify command.
See Also
- ARC Paper (arXiv:2511.09008) (PDF) - Research foundation
- Language Syntax Reference - Full syntax documentation
- Effects System - How contracts interact with effects
- Citations & Bibliography - Complete academic references