\section{Type System}
\label{sec:types}

(This section is still a work in progress)

\newcommand{\tcheck}[3]{#1 \vdash #2 \Leftarrow #3}
\newcommand{\tinfer}[3]{#1 \vdash #2 \Rightarrow #3}
\newcommand{\msail}[1]{\text{\lstinline[mathescape]+#1+}}

\subsection{Blocks}
\label{subsec:blocks}

\[
\frac{\tcheck{\Gamma}{E_0}{\text{\lstinline+bool+}}
      \qquad
      \tcheck{\Gamma}{M}{\text{\lstinline+string+}}
      \qquad
      \tcheck{\mathrm{FlowThen}(\Gamma, E_0)}{\text{\lstinline[mathescape]+\{$E_1$; $\ldots$; $E_n$\}+}}{A}}
     {\tcheck{\Gamma}{\text{\lstinline[mathescape]+\{assert($E_0$, $M$); $E_1$; $\ldots$; $E_n$ \}+}}{A}}
\]

\[
\frac{\tcheck{\mathrm{BindAssignment}(\Gamma, L_0, E_0)}{\text{\lstinline[mathescape]+\{$E_1$; $\ldots$; $E_n$\}+}}{A}}
     {\tcheck{\Gamma}{\text{\lstinline[mathescape]+\{$L_0$ = $E_0$; $E_1$; $\ldots$; $E_n$ \}+}}{A}}
\]

\[
\frac{\tcheck{\Gamma}{E_0}{\text{\lstinline+unit+}}
      \qquad
      \tcheck{\Gamma}{\text{\lstinline[mathescape]+\{$E_1$; $\ldots$; $E_n$\}+}}{A}}
     {\tcheck{\Gamma}{\text{\lstinline[mathescape]+\{$E_0$; $E_1$; $\ldots$; $E_n$ \}+}}{A}}
\]

\[
\frac{\tcheck{\Gamma}{E}{A}}
     {\tcheck{\Gamma}{\text{\lstinline[mathescape]+\{$E$\}+}}{A}}
\]

\subsection{Let bindings}

Note that \lstinline[mathescape]+{let x = y; $E_0$; $\ldots$; $E_n$}+
is equivalent to \lstinline[mathescape]+{let x = y in {$E_0$; $\ldots$; $E_n$}}+,
which is why there are no special cases for let bindings in Subsection~\ref{subsec:blocks}.

\[
\frac{\tcheck{\Gamma}{E_0}{B}
      \qquad
      \tcheck{\mathrm{BindPattern}(\Gamma, P, B)}{E_1}{A}}
     {\tcheck{\Gamma}{\msail{let $\;P\;$ : $\;B\;$ = $\;E_0\;$ in $\;E_1$}}{A}}
\]

\[
\frac{\tinfer{\Gamma}{E_0}{B}
      \qquad
      \tcheck{\mathrm{BindPattern}(\Gamma, P, B)}{E_1}{A}}
     {\tcheck{\Gamma}{\msail{let $\;P\;$ = $\;E_0\;$ in $\;E_1$}}{A}}
\]

\paragraph{Pattern bindings} The $\mathrm{BindPattern}$ and $\mathrm{BindPattern}'$ functions are used to bind patterns into an environment. The first few cases are simple, if we bind an identifier $x$ against a type $T$, where $x$ is either immutable or unbound, then $x : T$ is added to the environment. If we bind a type against a wildcard pattern, then the environment is returned unchanged. An \lstinline+as+ pattern binds its variable with the appropriate type then recursively binds the rest of the pattern. When binding patterns we always bind against the base type, and bring existentials into scope, which is why $\mathrm{BindPattern}$ does this and then calls the $\mathrm{BindPattern}'$ function which implements all the cases.
\begin{align*}
  \mathrm{BindPattern}(\Gamma, P, T) &= \mathrm{BindPattern}'(\Gamma \lhd T, P, \mathrm{Base}(T))\\
  \mathrm{BindPattern}'(\Gamma, x, T) &= \Gamma \oplus x : T, \tag{$x$ is unbound or immutable}\\
  \mathrm{BindPattern}'(\Gamma, \msail{_}, T) &= \Gamma,\\
  \mathrm{BindPattern}'(\Gamma, \msail{$P\;$ as $\;x$}, T) &= \mathrm{BindPattern}(\Gamma \oplus x : T, P, T). \tag{$x$ is unbound or immutable}
\end{align*}
If we try to bind a numeric literal $n$ against a type
\lstinline[mathescape]+int($N$)+ then we add a constraint to the
environment that the nexp $N$ is equal to $n$.
\begin{align*}
\mathrm{BindPattern}'(\Gamma, n, \msail{int($N$)}) &= \Gamma \oplus (N = n).
\end{align*}
We also have some rules for typechecking lists, as well as user
defined constructors in unions (omitted here)
\begin{align*}
  \mathrm{BindPattern}'(\Gamma, [], \msail{list($A$)}) &= \Gamma,\\
  \mathrm{BindPattern}'(\Gamma, \msail{$P_{\mathit{hd}}\;$ :: $\;P_{\mathit{tl}}$}, \msail{list($A$)})
  &= \mathrm{BindPattern}(\mathrm{BindPattern}(\Gamma,P_{\mathit{hd}},A),P_{\mathit{tl}},\msail{list($A$)}).
\end{align*}

The pattern binding code follows a similar structure to the
bi-directional nature of the typechecking rules---the
$\mathrm{BindPattern}$ function acts like a checking rule where we
provide the type, and there is also an $\mathrm{InferPattern}$
function which acts like bind pattern but infers the types from the
patterns. There is therefore a final case
$\mathrm{BindPattern}(\Gamma, P, T) = \Gamma'$ where
$(\Gamma', T') = \mathrm{InferPattern}(\Gamma, P)$ and $T \subseteq T'$.

The $\mathrm{InferPattern}$ function is defined by the following cases
\begin{align*}
  \mathrm{InferPattern}(\Gamma,x) &= (\Gamma, T_{\mathit{enum}}), \tag{$x$ is an element of enumeration $T_{\mathit{enum}}$}\\
  \mathrm{InferPattern}(\Gamma,L) &= (\Gamma, \mathrm{InferLiteral}(L)), \tag{$L$ is a literal}\\
  \mathrm{InferPattern}(\Gamma,\msail{$P\;$ : $\;T$}) &= (\mathrm{BindPattern}(\Gamma,P,T), T).
\end{align*}

\paragraph{Type patterns} There is one additional case for $\mathrm{BindPattern}'$ which we haven't discussed. \TODO{type patterns}

\subsection{If statements}

\[
\frac{\tcheck{\Gamma}{E_{\mathit{if}}}{\msail{bool}}
      \qquad
      \tcheck{\mathrm{FlowThen}(\Gamma, E_{\mathit{if}})}{E_{\mathit{then}}}{A}
      \qquad
      \tcheck{\mathrm{FlowElse}(\Gamma, E_{\mathit{if}})}{E_{\mathit{else}}}{A}}
     {\tcheck{\Gamma}{\msail{if $\;E_{\mathit{if}}\;$ then $\;E_{\mathit{then}}\;$ else $\;E_{\mathit{else}}\;$}}{A}}
\]

\subsection{Return}

When checking the body of a function, the expected return type of the
function is placed into the context $\Gamma$.

\[
\frac{\tcheck{\Gamma}{E}{\mathrm{Return}(\Gamma)}}
     {\tcheck{\Gamma}{\msail{return($E$)}}{A}}
\]

\subsection{Functions}

Depending on the context, functions can be either checked or
inferred---although the only difference between the two cases is that
in the checking case we can use the expected return type to resolve
some of the function quantifiers, whereas in the inferring case we
cannot.

\begin{align*}
  \frac{
    f : \forall Q, C.(B_0,\ldots,B_n) \rightarrow R \in \Gamma
    \quad \textsc{InferFun}(\Gamma,Q,C,(B_0,\ldots,B_n),R,(x_0,\ldots,x_n)) = R'
  } {
    \tinfer{\Gamma}{f(x_0, \ldots, x_n)}{R'}
  }
\end{align*}

\begin{align*}
  \frac{
    f : \forall Q, C.(B_0,\ldots,B_n) \rightarrow R \in \Gamma
    \quad \textsc{CheckFun}(\Gamma,Q,C,(B_0,\ldots,B_n),R,(x_0,\ldots,x_n),R')
  } {
    \tcheck{\Gamma}{f(x_0, \ldots, x_n)}{R'}
  }
\end{align*}

The rules for checking or inferring functions are rather more
complicated than the other typing rules and are hard to describe in
purely logical terms, so they are instead presented as an algorithm in
Figure~\ref{fig:funapp}. Roughly the inference algorithm works as
follows:

\begin{enumerate}
\item \textsc{InferFun} takes as input the typing context $\Gamma$, the
  list of quantifiers $Q$ (a list of type variable/kind pairs), a
  constraint $C$, the function argument types $B_0\ldots B_n$, the
  function return type $R$, and finally this list of argument
  expressions the function is applied to $x_0\ldots x_n$.

\item We create an empty list of unsolved typing goals
  (expression/type pairs) called $\mathit{unsolved}$, a list of
  constraints $\mathit{Constraints}$, and a set of existential
  variables $\mathit{Existentials}$.

\item We iterate over each argument expression and type $x_m$ and
  $B_m$, if $x_m$ contains free type variables in $Q$ we infer the
  type of $x_n$ and attempt to unify that inferred type with $B_m$. If
  this unification step fails we add $(x_m, B_m)$ to the list of
  unsolved goals. This unification step may generate new existential
  variables and constraints which are added to $\mathit{Existentials}$
  and $\mathit{Constraints}$ as needed. The results of this
  unification step are used to resolve the universally-quantified type
  variables in $Q$. If $x_m$ does not contain free type variables in
  $Q$, then we simply check it against $B_m$.

\item After this loop has finished we expect all the type variables in
  $Q$ to have been resolved. If not, we throw a type error.

\item We now try to prove the function's constraint $C$ using the
  resolved type variables, and check any remaining function arguments
  in $\mathit{unsolved}$.

\item Finally, we add any new existentials and constraints to the
  function's return type $R$, simplifying if at all possible (using
  \textsc{SimplifyExist}), before returning this type as the inferred
  type of the function.
\end{enumerate}

\noindent The \textsc{CheckFun} calls the \textsc{InferFun} function, but it
takes an additional $X$ argument which the the required return type in
the context where the function being checked is called. It
additionally unifies the function's declared return type with the
expected return type, and uses this to resolve any quantifiers in $Q$,
provided that the return type is not existentially quantified. It may
also be required to coerce $R$ into $X$.

\begin{figure}[p]
\begin{algorithmic}[1]
  \Function{InferFun}{$\Gamma,Q, C, (B_0,\ldots,B_n), R, (x_0, \ldots, x_n)$}
  \State $\mathit{unsolved}\gets []$;
  $\mathit{Constraints}\gets []$;
  $\mathit{Existentials}\gets \emptyset$
  \ForAll{$m \in 0, \ldots, n$}
    \If{$B_m$ contains type variables in $Q$}
    \State $\Gamma \vdash x_m \Rightarrow E$
    \Comment Infer the type of $x_m$ as $E$
      \State $\mathit{unifiers}, \mathit{existentials}, \mathit{constraint} \gets$ \Call{CoerceAndUnify}{$\Gamma,E,B$}
      \If{\textsc{CoerceAndUnify} failed with \textsc{UnificationError}}
        \State $\mathit{unsolved}\gets (x_m,B_m) : \mathit{unsolved}$
        \State \textbf{continue}
        \Comment Skip to next iteration of loop
      \ElsIf{$\mathit{existentials}$ is not empty}
        \State Add type variables $\mathit{existentials}$ to $\Gamma$
        \State Add constraint $\mathit{constraint}$ to $\Gamma$
        \State $\mathit{Constraints}\gets \mathit{constraint} : \mathit{Constraints}$
        \State $\mathit{Existentials}\gets \mathit{existentials} \cup \mathit{Existentials}$
      \EndIf
      \ForAll{$(\mathit{nvar}, \mathit{nexp}) \in \mathit{unifiers}$}
        \State $B_0,...,B_n\gets B_0[\mathit{nvar} := \mathit{nexp}],\ldots,B_n[\mathit{nvar} := \mathit{nexp}]$
        \State $R\gets R[\mathit{nvar} := \mathit{nexp}]$;
        $C\gets C[\mathit{nvar} := \mathit{nexp}]$
        \State Remove $\mathit{nvar}$ from $Q$
      \EndFor
    \ElsIf{$B_m$ does not contain type variables in $Q$}
      \State $\tcheck{\Gamma}{x_m}{B_m}$
      \Comment Check type of $x_m$ against $B_m$
    \EndIf
  \EndFor
  \If{$Q$ is not empty}
    \State \textbf{raise} \textsc{TypeError}
    \Comment Unresolved universal quantifers
  \EndIf
  \State \Call{Prove}{$\Gamma, C$}
  \ForAll{$(x_m,B_m) \in \mathit{unsolved}$}
    $\tcheck{\Gamma}{x_m}{B_m}$
  \EndFor
  \State \Return \Call{SimplifyExist}{$\mathtt{exist}\ \mathit{Existentials}, \mathit{Constraints}.\ R$}
  \EndFunction\\

  \Function{CheckFun}{$\Gamma,Q,C,(B_0,\ldots,B_n),R,(x_0,\ldots,x_n),X$}
  \If{$X$ and $R$ are not existentially quantified}
    \State $\mathit{unifiers}, \_, \_ \gets$ \Call{Unify}{$\Gamma,R,X$}
    \If{\textsc{Unify} failed with \textsc{UnificationError}}
      \textbf{skip}
    \Else
      \ForAll{$(\mathit{nvar}, \mathit{nexp}) \in \mathit{unifiers}$}
        \State $B_0,...,B_n\gets B_0[\mathit{nvar} := \mathit{nexp}],\ldots,B_n[\mathit{nvar} := \mathit{nexp}]$
        \State $R\gets R[\mathit{nvar} := \mathit{nexp}]$;
        $C\gets C[\mathit{nvar} := \mathit{nexp}]$
        \State Remove $\mathit{nvar}$ from $Q$
      \EndFor
    \EndIf
  \EndIf
  \State $R'\gets$ \Call{InferFun}{$\Gamma,Q,C,(B_0,\ldots,B_n),R,(x_0,\ldots,x_n)$}
  \State \Return \Call{Coerce}{$R',X$}
  \EndFunction
\end{algorithmic}
\label{fig:funapp}
\caption{Inference and checking algorithms for function calls}
\end{figure}
