linear_generic_param: a linear value is passed to a generic parameter that has not opted in
A linear value is passed to a function that is generic in that parameter
(fn pass(x) do x end). An ordinary type variable is unrestricted, so the
function body could copy or drop the value, and the compiler does not look
inside the body to find out.
A program that triggers it
mod Main do
needs IO.Console
always_linear type Token = Token(Int)
fn consume(t : Token) : Int do
match t do Token(n) -> n end
end
fn pass(x) do x end
fn main(_console : Cap(IO.Console)) do
let t = pass(Token(1))
println(int_to_string(consume(t)))
end
end
The fix
If the generic function uses the parameter exactly once, mark it linear
where the function is defined (linear x : a). That opts it in to
receiving linear values, and its body is then checked to use x once.
Otherwise, consume the value at the call site instead.
mod Main do
needs IO.Console
always_linear type Token = Token(Int)
fn consume(t : Token) : Int do
match t do Token(n) -> n end
end
fn pass(linear x : a) : a do x end
fn main(_console : Cap(IO.Console)) do
let t = pass(Token(1))
println(int_to_string(consume(t)))
end
end
Why the rule exists
A type variable used to be unrestricted and instantiable with a linear
type, so fn dup(x) do (x, x) end turned one linear value into two.
Requiring the opt-in keeps generic code usable with ordinary values and
makes the functions that may receive linear values say so.
See also: the language reference.