11. Generics
Type application uses angle brackets in type position:
list: List<i32>
m: Map<string, User>
The grammar is unambiguous: < opens a type-argument list only in type-parsing context, after :, ->, type, impl, struct, trait, def's generic-params slot, actor, and inside an existing <…> list. Elsewhere < and > are comparison operators, and the expression parser never switches modes.
Inference rule
Type arguments are inferred from value arguments at the call site, or from the surrounding type context: a typed let, a function-parameter type, or the return-type position of the enclosing function. There is no syntax for supplying type arguments inline to an expression. There is no parse<i32>("42") and no equivalent.
A required function type also constrains generic arguments inside throws payloads. Rows are unordered sets, and substitution removes duplicate effects. The checker accepts one most general assignment; incompatible assignments produce H0524 after argument and result constraints have settled. Ordinary function values require equal rows, while a closure may perform a subset of its slot's row.
Where inference cannot pin a type parameter, annotate the binding:
xs: List<i32> = List.empty() # the element type is pinned by the annotation
count = xs.length
The compiler emits a teaching diagnostic in three cases:
- A user writes
f<T>(args)orf::<T>(args)in expression position. The error says type arguments cannot be supplied inline and points at the typed-binding fix. - A let-binding without a type annotation leaves a type parameter unconstrained. The error says cannot infer type for
<name>and points at the same fix. - A call leaves a bounded parameter unpinned that the callee dispatches through statically:
def fresh<C: Blanker>() -> i32whose body callsC.blank(), called asfresh()with nothing pinningC. There is no impl for that call to reach, and the error says cannot tell which type this call'sC: Blankerbound applies to and names the callee (H0555). A bounded parameter nothing pins is otherwise fine:Set.empty()never calls through its bound, and a value-receiver dispatch,x == yon aC, needs a value ofC, which a parameter nothing pinned never had.Ok(1) == Ok(1)leaves theErrpayload's type open and is accepted.
The cost is that an API whose type parameter appears only in return position with no value parameter (empty<T>() -> List<T>, size_of<T>) needs either a value parameter or a typed binding at every call site. In return, the syntax is uniform, with no second-class escape hatch and no inline-type-argument commitment locking <> out of a future alternative.
Single-uppercase-letter names are reserved for type parameters
A bare single uppercase letter in type position (T, K, V) is always an implicit type parameter and never a concrete type. A struct, type or actor declared with a single-uppercase-letter name is therefore rejected at the declaration: such a name could never be referenced as itself. Give user-defined types a name of two or more characters (Point, Cmd, Tree). The rule runs in both directions, and an explicit <...> list is no exception to it. A type parameter is a single uppercase letter wherever it is declared, and def pick<Item>(…), struct Box<Item>, impl<Key, Val> … and a trait member's own def choose<Item>(…) are all rejected at the declaration (H0634). It is a rule and no convention. A multi-letter name in a <...> list parses, binds nothing, and resolves to an opaque nominal type: the declaration looks fine and every call fails instead with type mismatch: expected Item, found i32, naming a type the reader never declared. One position is exempt. A trait's own parameter list (trait Add<Rhs = Self>, trait Scale<Factor>) has its parameters bound by the trait machinery and not by the name's form, a longer name there binds correctly, and it remains legal.
The lowercase counterpart applies to effect rows. A bare single lowercase letter inside […] (e, r) is an effect variable (§6) and never an effect name. Built-in and user effects are multi-letter (io, fs, Database) or capitalised (Crash), and the two never collide.