In the type of twoSeparateInts, the different regions variables on each of the Int constructors means that they do not alias. This in turn means that it is safe to treat one as Const and the other as Mutable.

But what happens if we partially apply f? The standard type system will re-generalize the type for the new binding and we're left with:

f_unit :: forall %r1. () -> Int %r1
f_unit = f ()

We've now got a function which returns the sameInt every time we call it, but the type says it's supposed to be fresh! The problem here is that x was free in our original definition of g so is shared between applications of it.

Closure typing for region sharing

Closure typing is used to track the sharing of regions between function calls.

The type inferred for f is actually:

f :: forall %r0
. () -> () -($c0)> Int %r0
:- $c0 = x : %r0

The $c0 annotation tells us that this function has a object free in its closure, and that the object contains region %r0. The x : %r0 syntax gives a name to this term, and is pronounced "x of region zero".

If we use this new type and apply the first argument we have:

f_unit :: () -($c0)> Int %r0
:- $c0 = x : %r0

This type says that f_unit is a function that takes a unit value and returns an Int, but the Int is free in its closure so is shared by all calls to it. The type system does not generalise regions which are free in these closures.