Type checking and source contracts#
The type checker decides whether source operations satisfy Manuscript’s rules before the compiler generates Go. The fact that a value can be represented in Go does not make every use of it legal in Manuscript.
Required checks#
Accept source according to the normative grammar ; then resolve names and check the compatibility rules . Each rejected program must identify the violated source rule. Backend assignability and Go compiler acceptance are not substitutes for those checks.
| Source rule | Checker responsibility |
|---|---|
| Explicit function signatures | Check parameter and result types against calls and returns |
| Names and scopes | Collect module signatures, reject duplicate names, resolve locals in declaration order, and check assignments against fixed mutable binding types |
| Operators | Use the closed precedence and operand table; enforce Bool conditions and short-circuit evaluation without implicit numeric conversion |
| Function values | Preserve parameter labels/order and exact types; require explicit specialization of generic function values and contextual anonymous parameter types and inferred anonymous results |
| Return completeness | Allow Unit fallthrough/bare returns; reject reachable non-Unit fallthrough; track Never and function-local loop/return boundaries |
| Argument labels | Resolve optional labels and positional arguments left to right to unfilled parameters, preserving matching-name shorthand; apply the same rule to constructors, methods and function values; reject unknown labels, duplicate arguments, excess positional arguments, and missing required arguments |
| List literals | Use the canonical standard List from the prelude; check homogeneous element types and use annotations or the expected parameter type for empty lists |
| Typed tasks | Infer Task[T] from the ordinary generic start signature; check each join against Result[T, ExecutionError] |
| Destructuring bindings | Check positional arity, record fields, renaming, nesting, and duplicate bindings; infer each local’s type independently; see destructuring bindings |
| Nominal records and tagged alternatives | Preserve type identity and check declared fields and cases |
| Expected types | Propagate known result context through literals, fields, parentheses, and generic calls; reject ambiguous or conflicting inference |
| Exhaustive match | Check the scrutinee alternative, positional payload arity/bindings, exact qualified cases, missing alternatives, duplicate arms, and final nonredundant wildcard |
| Generic bounds | Check arity, invariant arguments, argument and expected-result inference, every nested application’s bounds, and generic bodies under their declared assumptions |
| Recursive types and specialization | Permit direct and mutual recursive data; reject expanding generic type/function specialization, including signature references, mutual calls, and specialized function values |
| Equality and hashing | Derive only the specified properties; reject Float/collection keys and data containing ineligible components |
| Explicit implementations | Match substituted operation names/labels/order/types exactly, check generic bodies and receiver-determined parameters, reject overlap ignoring bounds, enforce module-local extension visibility, and require explicit contract views |
| Standard bindings | Resolve the minimal intrinsic prelude and explicit standard imports by canonical identity; check ordinary function signatures and exact contract views. Passing values requires no sharing bound; queue synchronization is the caller’s responsibility |
| Public signatures | Reject internal nominal types leaking through exported fields, signatures, bounds, or operation surfaces |
| Iteration | Admit List/Set/Map only, bind fixed iteration names for elements/MapEntry references, evaluate iterable once, and reject loop control outside the current function’s loops |
| Result propagation | Recognize the canonical standard Result identity; require the same exact error type at a try expression in the current function; do not infer missing operand type arguments backward |
| String literals | Validate escape/scalar syntax, support universal value conversion, and preserve left-to-right evaluation |
These requirements derive from the core language guide
, with accepted and rejected modules in core conformance
. The rules specify observable inference and compatibility; checker data structures and internal pass organization remain implementation choices. A module-level test body is a zero-parameter Unit function for static checking: ordinary local scopes, bare-return/fallthrough rules, and Result propagation restrictions apply. Test discovery and runner execution remain separate tooling contracts.
Type information feeds typed IR and generated representations .