Section 1: Type System Foundation
Goal: Fix type checking to properly use type annotations
SPEC:
spec/08-types.md,spec/09-properties-of-types.md,spec/10-declarations.md
Status: COMPLETE [done] (2026-02-13). Core (1.1-1.4) verified 2026-02-10. 1.1 all LLVM AOT tests 2026-02-13. 1.1A constant folding 2026-02-13. 1.1B ? LLVM support 2026-02-13. 1.6 type system slots (LifetimeId, ValueCategory, Borrowed tag, StructDef category) + parser &T error + keyword rejection verified 2026-02-13.
Known Bug (RESOLVED): let bindings directly in @main body previously crashed (type_interner.rs index out of bounds). Fixed as of 2026-02-13 — type_interner.rs was removed during hygiene refactors. 6 regression tests added.
1.1 Primitive Types
-
Implement:
inttype — spec/08-types.md § int [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 0; type checker handles int
- Ori Tests:
tests/spec/types/primitives.ori— 162 tests (all pass) - LLVM Support:
TypeInfo::Int→ i64 viastorage_type()+lower_int()in codegen - AOT Tests:
ori_llvm/tests/aot/spec.rs— 12 AOT tests using int
-
Implement:
floattype — spec/08-types.md § float [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 1; type checker handles float
- Ori Tests:
tests/spec/types/primitives.ori— float literal, negative, scientific, annotated, arithmetic, comparison tests - LLVM Support:
TypeInfo::Float→ f64 viastorage_type()+lower_float()in codegen - AOT Tests:
ori_llvm/tests/aot/spec.rs— 4 AOT tests (literals, arithmetic, comparison, negation) [done] (2026-02-13)
-
Implement:
booltype — spec/08-types.md § bool [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 2; type checker handles bool
- Ori Tests:
tests/spec/types/primitives.ori— bool literal, logic, short-circuit tests - LLVM Support:
TypeInfo::Bool→ i1 viastorage_type()+lower_bool()in codegen - AOT Tests:
ori_llvm/tests/aot/spec.rs— 7 AOT tests using bool
-
Implement:
strtype — spec/08-types.md § str [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 3; type checker handles str
- Ori Tests:
tests/spec/types/primitives.ori— str literal, equality, concatenation tests - LLVM Support:
TypeInfo::Str→ {i64 len, ptr data} viastorage_type()+lower_string()in codegen - AOT Tests:
ori_llvm/tests/aot/spec.rs— 1 AOT test (print_string)
-
Implement:
chartype — spec/08-types.md § char [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 4; type checker handles char
- Ori Tests:
tests/spec/types/primitives.ori— char literal, equality tests - LLVM Support:
TypeInfo::Char→ i32 viastorage_type()+lower_char()in codegen - AOT Tests:
ori_llvm/tests/aot/spec.rs— 2 AOT tests (literals, comparison) [done] (2026-02-13)
-
Implement:
bytetype — spec/08-types.md § byte [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 5; type checker handles byte
- Ori Tests:
tests/spec/types/primitives.ori— byte conversion, equality tests - LLVM Support:
TypeInfo::Byte→ i8 viastorage_type() - AOT Tests:
ori_llvm/tests/aot/spec.rs— 1 AOT test (basics, equality, boundary values); fixed byte codegen bug (i64→i8 store mismatch) [done] (2026-02-13)
-
Implement:
voidtype — spec/08-types.md § void [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 6 (Unit); type checker handles void
- Ori Tests:
tests/spec/types/primitives.ori— void function return tests - LLVM Support:
TypeInfo::Unit→ i64 viastorage_type()+lower_unit()(LLVM void cannot be stored) - AOT Tests:
ori_llvm/tests/aot/spec.rs— 5 AOT tests using void return
-
Implement:
Nevertype — spec/08-types.md § Never [done] (2026-02-10)- Rust Tests: Type pool pre-interned at index 7; type checker handles Never
- Ori Tests:
tests/spec/types/never.ori— 21 tests (all pass) - LLVM Support:
TypeInfo::Never→ i64 viastorage_type() - AOT Tests:
ori_llvm/tests/aot/spec.rs— 2 AOT tests (panic coercion, multi-type conditional branches) [done] (2026-02-13)
Note: Also fixed parser bug where type keywords (int, float, etc.) couldn’t be used as builtin conversion function calls.
1.1A Duration and Size Types
Proposal: proposals/approved/duration-size-types-proposal.md
Formalize Duration and Size primitive types with literal syntax, arithmetic, and conversion methods.
Lexer
-
Implement: Duration literal tokenization with all units (ns, us, ms, s, m, h) [done] (2026-02-10)
- Rust Tests:
oric/tests/phases/parse/lexer.rs— 10+ duration tests (units, decimal, many digits) - Ori Tests:
tests/spec/lexical/duration_literals.ori— 70+ tests - LLVM Support:
lower_duration()in codegen — Duration → i64 (nanosecond precision) - AOT Tests:
ori_llvm/tests/aot/spec.rs— 4 AOT tests (literals, negative, arithmetic, comparison) [done] (2026-02-13)
- Rust Tests:
-
Implement: Size literal tokenization with all units (b, kb, mb, gb, tb) [done] (2026-02-10)
- Rust Tests:
oric/tests/phases/parse/lexer.rs— 5+ size tests - Ori Tests:
tests/spec/lexical/size_literals.ori— 70+ tests - LLVM Support:
lower_size()in codegen — Size → i64 (bytes) - AOT Tests:
ori_llvm/tests/aot/spec.rs— 3 AOT tests (literals, arithmetic, comparison) [done] (2026-02-13)
- Rust Tests:
-
Implement: Error for floating-point prefix on duration/size literals [done] (2026-02-10)
- Rust Tests:
oric/tests/phases/parse/lexer.rs— float_duration/size error token tests - Note: Parse errors (E0911) cannot use
#[compile_fail]which is for type errors only. Rust-level tests provide complete coverage.
- Rust Tests:
Type System
-
Implement: Duration type representation — spec/08-types.md § Duration [done] (2026-02-10)
- Rust Tests: Type pool pre-interned at index 9;
TypeInfo::Duration - Ori Tests:
tests/spec/types/primitives.ori— Duration type tests
- Rust Tests: Type pool pre-interned at index 9;
-
Implement: Size type representation — spec/08-types.md § Size [done] (2026-02-10)
- Rust Tests: Type pool pre-interned at index 10;
TypeInfo::Size - Ori Tests:
tests/spec/types/primitives.ori— Size type tests
- Rust Tests: Type pool pre-interned at index 10;
Arithmetic Operations
-
Implement: Duration arithmetic (+, -, *, /, %, unary -) [done] (2026-02-10)
- Ori Tests:
tests/spec/types/primitives.ori— Duration arithmetic tests - Verified:
1s + 500ms == 1500ms,2s * 3 == 6s,-(1s) == -1s(viaori parse/cargo st) - LLVM Support: Duration codegen exists (i64 arithmetic on nanosecond values)
- AOT Tests: Covered by
test_aot_duration_arithmeticinspec.rs[done] (2026-02-13)
- Ori Tests:
-
Implement: Size arithmetic (+, -, *, /, %) [done] (2026-02-10)
- Ori Tests:
tests/spec/types/primitives.ori— Size arithmetic tests - Verified:
1kb + 500b == 1500b,2kb * 3 == 6kb(viacargo st) - LLVM Support: Size codegen exists (i64 arithmetic on byte values)
- AOT Tests: Covered by
test_aot_size_arithmeticinspec.rs[done] (2026-02-13)
- Ori Tests:
-
Implement: Compile error for unary negation on Size [done] (2026-02-10)
- Verified:
-(1kb)→ E2001 “cannot negateSize: Size values must be non-negative”
- Verified:
-
Implement: Runtime panic for Duration overflow [done] (2026-02-13)
- Ori Tests:
tests/spec/types/duration_overflow.ori— 15 tests (8 #fail overflow/panic, 7 boundary/identity) - Verified: Checked arithmetic in evaluator panics on add/sub/mul/div/mod/neg overflow, div-by-zero, mod-by-zero
- Ori Tests:
-
Implement: Runtime panic for negative Size result [done] (2026-02-13)
- Ori Tests:
tests/spec/types/size_overflow.ori— 15 tests (9 #fail overflow/panic, 6 boundary/identity) - Verified: Checked arithmetic panics on sub→negative, add overflow, mul overflow, mul/div by negative, div/mod by zero
- Ori Tests:
Conversion Methods
-
Implement: Duration extraction methods (.nanoseconds(), .microseconds(), etc.) [done] (2026-02-10)
- Verified:
1s.nanoseconds() == 1000000000,1s.microseconds() == 1000000,1s.milliseconds() == 1000,1s.seconds() == 1
- Verified:
-
Implement: Duration factory methods (Duration.from_seconds(), etc.) [done] (2026-02-10)
- Verified:
Duration.from_seconds(5) == 5s - Note: Associated function syntax implemented in Section 5.9
- Verified:
-
Implement: Size extraction methods (.bytes(), .kilobytes(), etc.) [done] (2026-02-10)
- Verified:
1kb.bytes() == 1000,1mb.kilobytes() == 1000
- Verified:
-
Implement: Size factory methods (Size.from_bytes(), etc.) [done] (2026-02-10)
- Verified:
Size.from_bytes(1024) == 1024b - Note: Associated function syntax implemented in Section 5.9
- Verified:
Trait Implementations
-
Implement: Eq, Comparable for Duration [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_comparable.ori— 16 tests (all pass) - Verified:
1s > 500ms == true
- Ori Tests:
-
Implement: Eq, Comparable for Size [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_comparable.ori— 16 tests (all pass)
- Ori Tests:
-
Implement: Clone, Printable for Duration [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_clone_printable.ori— 26 tests (all pass)
- Ori Tests:
-
Implement: Clone, Printable for Size [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_clone_printable.ori— 26 tests (all pass)
- Ori Tests:
-
Implement: Hashable for Duration and Size [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_hashable.ori— 13 tests (all pass)
- Ori Tests:
-
Implement: Default for Duration and Size (0ns and 0b) [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_default.ori— 10 tests (all pass)
- Ori Tests:
-
Implement: Sendable for Duration and Size [done] (2026-02-10)
- Ori Tests:
tests/spec/types/duration_size_sendable.ori— 8 tests (all pass)
- Ori Tests:
Constant Folding
- Implement: Duration/Size constant folding in
ori_canon[done] (2026-02-13)- Added
extract_const_value()arms forCanExpr::Duration/CanExpr::Size→ConstValue - Added
fold_binary()rules: Duration±Duration, Size±Size, Durationint, Sizeint, Duration/int, Size/int, mod, all comparisons - Added
fold_unary()rule: Duration negation (Size negation correctly rejected) - Rust Tests: 14 unit tests in
ori_canon/src/const_fold.rs— addition, subtraction, comparison, cross-unit equality, negation, mul/div with int, overflow/negative rejection - Ori Tests:
tests/spec/types/duration_size_const.ori— 18 tests covering constant Duration/Size in let bindings, cross-unit arithmetic, comparisons, mixed int operations - LLVM Support: Already handled —
lower_constant()dispatches tolower_duration()/lower_size()with unit conversion
- Added
1.1B Never Type Semantics
Proposal: proposals/approved/never-type-proposal.md
Formalize the Never type as the bottom type with coercion rules, type inference behavior, and pattern matching exhaustiveness.
Status: All Never type features implemented and verified [done] (2026-02-13). Result type layout bug fixed — TypeInfoStore resolves type variables via Pool::resolve_fully(); Result::unwrap() coerces payload to ok type.
Coercion
-
Implement: Never coerces to any type T in assignment contexts [done] (2026-02-10)
- Ori Tests:
tests/spec/types/never.ori— 21 tests (all pass) - LLVM Support: Never coercion works in AOT — conditional branches with panic() produce correct values [done] (2026-02-13)
- AOT Tests:
ori_llvm/tests/aot/spec.rs— 2 AOT tests (panic coercion, multi-type conditional branches) [done] (2026-02-13)
- Ori Tests:
-
Implement: Never coerces in conditional branches [done] (2026-02-10)
- Verified:
if true then 42 else panic(msg: "unreachable")returns int correctly
- Verified:
-
Implement: Never coerces in match arms [done] (2026-02-10)
- Verified:
match(Red, Red -> 42, Green -> panic(msg: "nope"), Blue -> panic(msg: "nope"))returns int
- Verified:
Expressions Producing Never
-
Implement: panic(msg:) returns Never [done] (2026-02-10)
- Verified:
if true then 42 else panic(msg: "x")type-checks as int (panic coerces to int)
- Verified:
-
Implement: todo() and todo(reason:) return Never [done] (2026-02-10)
- Verified:
if true then 42 else todo()type-checks as int
- Verified:
-
Implement: unreachable() and unreachable(reason:) return Never [done] (2026-02-10)
- Verified:
if true then 42 else unreachable()type-checks as int
- Verified:
Pending (Future Work)
-
Implement: break/continue have type Never inside loops [done] (2026-02-10)
- Verified:
loop(break 42)returns int (break value used as loop result) - LLVM Support: Verified in AOT [done] (2026-02-13) — 5 tests: basic break value, conditional break, break Never coercion, continue Never coercion, break+continue combined
- Verified:
-
Implement: Early-return path of ? operator has type Never [done] (2026-02-13)
- Bug Fix:
ControlAction::Propagatewas not caught at function call boundaries —?errors leaked through all call frames instead of becoming the function’s return value. Fixed infunction_call.rswithcatch_propagation(). - Ori Tests:
tests/spec/control_flow/never_propagation.ori— 14 tests (Result and Option propagation, chaining, nested calls, conditional branches, multiple ? in same expression) - LLVM Support: Fixed —
TypeInfoStorenow followsPool::resolve_fully()forTag::Vartype variables;Result::unwrap()coerces payload to ok type [done] (2026-02-13) - AOT Tests: 11 AOT tests in
ori_llvm/tests/aot/spec.rs— Result/Option constructors,?operator (ok unwrap, err propagation, chained), method dispatch (is_ok/is_err/unwrap)
- Bug Fix:
-
Implement: Infinite loop (no break) has type Never [done] (2026-02-13)
- Fix:
infer_loop()returnedIdx::UNITfor unresolved break type; now returnsIdx::NEVER. Abreak(even without value) unifies with Unit, so unresolved truly means no break exists. - Rust Tests: Updated
test_infer_infinite_loopto assertIdx::NEVER - Verified:
@diverge () -> int = loop(())type-checks — Never coerces to int
- Fix:
-
Implement: Never variants can be omitted from match exhaustiveness [done] (2026-02-13)
- Verified:
type MaybeNever = Value(v: int) | Impossible(n: Never)— match omitting Impossible passes - Added
is_variant_uninhabited()inori_canon/src/exhaustiveness.rs - 3 unit tests + 2 Ori spec tests in
tests/spec/patterns/exhaustiveness.ori
- Verified:
-
Implement: Error E2019 for Never as struct field type [done] (2026-02-13)
- Added
UninhabitedStructFieldvariant toTypeErrorKind - Check in
registration.rsduring struct type registration - Compile-fail test:
tests/compile-fail/never_struct_field.ori - Integration tests:
never_struct_field_rejected,never_in_sum_variant_allowed
- Added
-
Verify: Allow Never in sum type variant payloads [done] (2026-02-13)
- Already works —
type MaybeNever = Value(v: int) | Impossible(n: Never)compiles - Exhaustiveness checker correctly treats Never variants as uninhabited
- Integration test:
never_in_sum_variant_allowed
- Already works —
1.2 Parameter Type Annotations
-
Implement: Add
type_id_to_type()helper function [done] (2026-02-10)- Verified: Type annotations on parameters work (e.g.,
@add (a: int, b: int) -> int)
- Verified: Type annotations on parameters work (e.g.,
-
Implement: Use
Param.tywhen present ininfer_function_signature()[done] (2026-02-10)- Verified:
@greet (name: str) -> str = namecorrectly infers str → str
- Verified:
-
Implement: Use declared return type when present [done] (2026-02-10)
- Verified:
@typed_return () -> int = 42correctly uses declared return type
- Verified:
-
Implement: Handle
TypeId::INFERfor unannotated parameters [done] (2026-02-10)- Verified:
@infer_param (x) -> int = xcorrectly infers x: int from context
- Verified:
1.3 Lambda Type Annotations
-
Implement: Typed lambda parameters
(x: int) -> x + 1[done] (2026-02-10)- Verified:
let f = (x: int) -> x + 1, f(41)returns 42
- Verified:
-
Implement: Explicit return type
(x: int) -> int = x + 1[done] (2026-02-10)- Verified:
let f = (x: int) -> int = x * 2, f(21)returns 42
- Verified:
1.4 Let Binding Types
- Implement: Type annotation in
let x: int = ...[done] (2026-02-10)- Verified:
let x: int = 42,let x: float = 3.14work correctly (insiderun()) - Bug fixed:
let x: int = 42directly in@mainbody no longer crashes [done] (2026-02-13) —type_interner.rsremoved during hygiene refactors; 6 regression tests added inoric/tests/phases/common/typecheck.rs
- Verified:
1.6 Low-Level Future-Proofing (Reserved Slots)
Proposal: proposals/approved/low-level-future-proofing-proposal.md
Reserve architectural space in the type system for future low-level features (inline types, borrowed views). No user-visible changes — only internal structure.
Type System Slots
-
Implement: Add
LifetimeIdtype toori_types[done] (2026-02-13)-
LifetimeId(u32)newtype withSTATICandSCOPEDconstants inori_types/src/lifetime.rs - 7 unit tests (roundtrip, display, equality, hash, size assertion)
- Salsa compatibility assertion in
lib.rs
-
-
Implement: Add
ValueCategoryenum toori_types[done] (2026-02-13)-
Boxed(default),Inline(reserved),View(reserved) inori_types/src/value_category.rs - 5 unit tests (default, predicates, display, size, hash)
- Salsa compatibility assertion in
lib.rs
-
-
Implement: Add
Borrowedvariant toTagenum [done] (2026-02-13)-
Tag::Borrowed = 34in two-child containers range, extra layout:[inner_idx, lifetime_id] - Updated all exhaustive matches:
tag.rs,pool/mod.rs,pool/format.rs,type_error/diff.rs,ori_arc/classify.rs,ori_llvm/type_info.rs - Note:
#[doc(hidden)]removed per clippy — variant is internal to compiler, fully visible
-
-
Implement: Add
categoryfield toStructDef[done] (2026-02-13)-
category: ValueCategoryfield onStructDef, default toValueCategory::Boxed - Updated all 4 construction sites:
registry/types.rs,output/mod.rs,ori_llvm/type_registration.rs(×2)
-
Syntax Reservation
-
Implement: Add
inlineas reserved keyword in lexer [done] (2026-02-10)- Recognized in
ori_lexer/src/keywords.rs(reserved-future list) - Produces E0015 error: “
inlineis reserved for future use” [done] (verified 2026-02-13)
- Recognized in
-
Implement: Add
viewas reserved keyword in lexer [done] (2026-02-10)- Recognized in
ori_lexer/src/keywords.rs(reserved-future list) - Produces E0015 error: “
viewis reserved for future use” [done] (verified 2026-02-13)
- Recognized in
-
Implement: Reserve
&in type position [done] (2026-02-13)- Parser detects
&inparse_type()and produces E1001: “borrowed references (&T) are reserved for a future version of Ori” - Recovers by parsing inner type, enabling continued parsing
- 3 parser tests:
&int,&MyType,&alone
- Parser detects
-
Implement: Parser rejects reserved keywords with helpful errors [done] (verified 2026-02-13)
- Lexer cooker produces
LexError::ReservedFutureKeywordwith E0015 for all 5 reserved-future keywords (asm,inline,static,union,view) - Token still interned as
Identfor parse recovery; error reported to user
- Lexer cooker produces
1.7 Section Completion Checklist
- 1.1 Primitive types complete — all 8 types verified in type checker + evaluator + LLVM codegen [done] (2026-02-10)
- 1.1A Duration/Size complete — lexer, type system, arithmetic, conversions, all 7 traits [done] (2026-02-10)
- 1.1B Never type fully implemented [done] (2026-02-13) — infinite loop→Never,
?propagation fix, exhaustiveness for Never variants, E2019, sum variant payloads,?LLVM support (fixed type variable leak + Result::unwrap coercion) - 1.2 Parameter type annotations complete [done] (2026-02-10)
- 1.3 Lambda type annotations complete [done] (2026-02-10)
- 1.4 Let binding types complete [done] (2026-02-10)
- 1.6 Low-level future-proofing complete [done] (2026-02-13) — LifetimeId, ValueCategory, Borrowed tag, StructDef category field,
&Tparser error, keyword rejection verified - LLVM AOT tests complete — all 8 primitive types have AOT tests [done] (2026-02-13); fixed byte codegen bug (i64→i8 store mismatch causing segfault)
- Loop/break/continue AOT tests — 5 tests verifying Never coercion in loops [done] (2026-02-13)
-
@mainlet binding bug fixed [done] (2026-02-13) —type_interner.rsremoved during hygiene refactors; 6 regression tests added
Section 1 complete. All subsections (1.1–1.4, 1.6) implemented and verified.