You call a generic function like any other function. The compiler figures out the concrete type from the immediate context.
Inference from an argument
identity type A |value A| -> A:
return value
;
value = identity(42)
Because 42 is an Int, A becomes Int for this call.
Inference from the result type
empty type A || -> {A}:
return {}
;
items {Int} = empty()
The left-hand side says the result is {Int}, so A becomes Int.
Generic function calls use ordinary call syntax. Type arguments are inferred from local evidence only.
Inference sources
identity type A |value A| -> A:
return value
;
empty type A || -> {A}:
return {}
;
value = identity(42)
typed_value Int = identity(42)
items {Int} = empty()
The concrete type for A can come from:
- immediate call arguments
- the immediate expected result type at a closed receiving site
What inference does not use
values = empty()
Inference does not use:
- later mutation
- later reads
- whole-program analysis
- HIR
- borrow validation
- distant return use
- expected parameter context from an outer call into a nested generic call
Use an intermediate annotation when a nested generic call would otherwise need evidence from its parent call.
empty type A || -> {A}:
return {}
;
consume |values {Int}|:
;
consume(empty())
items {Int} = empty()
consume(items)
Optional and fallible generic returns
Generic functions may return optional or fallible values when the concrete envelope is solved by immediate evidence.
wrap_optional type T |value T| -> T?:
return value
;
always_fail type T, E |fallback T, err E| -> T, E!:
return! err
;
maybe_name String? = wrap_optional("Ana")
value = always_fail(7, Error("bad")) catch |err| then 0
A bare none cannot infer an otherwise unknown parameter by itself.
Imported generic functions
Visible imported generic functions use the same local inference rules. There is no explicit call-site type argument syntax.
Cast boundary
Generic inference does not look through cast. The cast target must be selected after the generic call has already been solved.
Generic error parameter inference
A concrete callee error type does not specialise an otherwise unsolved generic error parameter merely because it appears inside the generic body. Immediate declaration and call-site evidence must still solve the parameter.
generic_fail type E || -> Int, E!:
return! Error("bad")
;
A generic error parameter must be solved by immediate call-site evidence, like any other generic parameter.
Explicit call-site syntax is rejected
All of these are rejected:
identity of Int(42)
identity<Int>(42)
identity[Int](42)
identity(42 Int)
Related concepts