v6 Semantics: static types on a dynamic runtime
Work through examples, try the reasoning yourself, then put it into practice.
View SlidesBefore you start
- Build v6 Type trees and understand v5 module/export resolution.
What you will practice
- Trace expected types through declarations, calls, and returns.
- Validate structural compatibility and exported signatures.
- Distinguish actual checker behavior from stronger unimplemented guarantees.
In this lesson
Lesson
3 min readv6 Semantics: static types on a dynamic runtime
Analyze now computes types as it checks scopes. Its public result remains
an ordered diagnostic slice; CompileModules consumes the original program AST.
The checker precomputes typed export interfaces: exported variables require
annotations, and exported functions require complete signatures.
Worked reconstruction
fn first(xs:array<number>)->number { return xs[0]; }
let values:array<number> = [];
let answer=first(values);
| Expression/context | Information supplied | Result |
|---|---|---|
| annotated values initializer | expected array | empty literal receives that type |
| values used as argument | declared array | matches first's parameter |
| xs[0] | array element type number, numeric index | expression type number |
| explicit return | expected number | compatible |
| answer initializer | function return number | infer answer as number |
The empty values array still makes first(values) fail at runtime. Type compatibility and bounds are different predicates.
Context has specific entry points
Expected types flow into annotated declaration initializers, typed call
arguments, and explicit return expressions. A plain assignment first infers
its RHS without the target type in this implementation: after
let xs:array<number> = [];, xs=[]; reports inability to infer the empty RHS.
Do not claim universal bidirectional inference. A nonempty xs=[1]; supplies
its own element type and can be checked structurally.
Array elements and map entries must be compatible with a common type. Static map keys are number, bool, or string; the older VM's ability to hash nil keys does not extend the v6 static key rule. Operators use their required types: number arithmetic/comparison, string+string, boolean logical operators. A typed imported function call checks argument count and types across the module boundary, unlike v5's member-name-only check.
Limits and diagnostic order
Nil is assignable to every type. Unknown is permissive internally to reduce
cascading mismatches, but source uses causing unknown can already have errors.
No all-path-return analysis or flow-sensitive narrowing is implemented.
fn f()->number {} can pass; later arithmetic on its nil result can fail.
Both sides of logical expressions are statically visited, even when runtime
short-circuits. For a wrong-arity call the checker reports arity before deeper
argument-type checks; do not use an ill-formed call to test a later mismatch.
Module-order/name checks, const rules, nested body scopes, and function-local loop contexts remain active alongside typing.
Debugging lab
A test expects xs=[] to inherit xs’s declared array type, and a lesson says every number-returning function must return on all paths. Which claims exceed this checker’s implementation?
Compare your diagnosis after attempting the lab
Plain assignment RHS inference does not receive the target type, unlike annotated initializers/call arguments/returns. The analyzer validates explicit returns but performs no all-path coverage proof. Test and describe those limits rather than silently promising a stronger system.
Transfer task
Write a typed exported function, call it correctly from a later module, then change only one argument type. Separately test wrong arity, an unknown export, and a correct type with an out-of-range array access; identify the earliest failure for each.
Carry forward
Carry an honestly bounded typed front end into the final capstone. Keep both rejected-static and accepted-runtime-failure examples as part of the course completion evidence.
Build semantic-analysis-v6. Keep a before/after trace of one failing test. Use the checkpoint to diagnose specific skills; passing it does not replace implementing and testing the artifact.
Practice sequence
Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.