\documentclass[acmsmall,nonacm]{acmart}

\bibliographystyle{ACM-Reference-Format}
\citestyle{acmauthoryear}

\RequirePackage{tikz}
\RequirePackage{scalerel}
\RequirePackage{xparse}
\RequirePackage{xifthen}

\usepackage{mathpartir}

\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{calc}
\usetikzlibrary{arrows.meta}

%% Invariants and Ghost ownership
% PDS: Was 0pt inner, 2pt outer.
% \boxedassert [tikzoptions] contents [name]
\tikzstyle{boxedassert_border} = [sharp corners,line width=0.2pt]
\NewDocumentCommand \boxedassert {O{} m o}{%
	\tikz[baseline=(m.base)]{
		%	  \node[rectangle, draw,inner sep=0.8pt,anchor=base,#1] (m) {${#2}\mathstrut$};
		\node[rectangle,inner sep=0.8pt,outer sep=0.2pt,anchor=base] (m) {${\,#2\,}\mathstrut$};
		\draw[#1,boxedassert_border] ($(m.south west) + (0,0.65pt)$) rectangle ($(m.north east) + (0, 0.7pt)$);
	}\IfNoValueF{#3}{^{\,#3}}%
}
\DeclareMathOperator*{\Sep}{\scalerel*{\ast}{\sum}}
\newcommand*{\ghost}[1]{\boxedassert[densely dashed]{#1}}
\newcommand*{\N}{\mathbb{N}}
\newcommand*{\Z}{\mathbb{Z}}
\newcommand{\wand}{\mathrel{-\!\!\ast}}
\newcommand{\core}[1]{\left| #1 \right|}
\newcommand{\proves}{\vdash}
\newcommand{\makes}{\dashv}
\newcommand{\constep}{\Rightarrow}
\newcommand{\makesto}{\dashv\!\constep}
\newcommand{\judgment}[2][]{\noindent\\\textbf{#1}\hspace{\stretch{1}}\fbox{$#2$}\nopagebreak}
\newcommand{\judgmentB}[3][]{\noindent\\\textbf{#1}\hspace{\stretch{1}}\fbox{$#2$}\ \ \fbox{$#3$}\nopagebreak}
\newcommand*{\axiom}[2][]{\infer[#1]{}{#2}}

\begin{document}

\title{Metamath C technical appendix}

%% Author with single affiliation.
\author{Mario Carneiro}
\affiliation{
  \institution{Carnegie Mellon University}
}

% \begin{abstract}
% Text of abstract \ldots.
% \end{abstract}

\maketitle

\section{Introduction}

This is an informal development of the theory behind the Metamath C language: the syntax and separation logic, as well as the lowering map to x86. For now, this is just a set of notes for the actual compiler. (Informal is a relative word, of course, and this is quite formally precise from a mathematician's point of view. But it is not mechanized.)

\section{Syntax}

The syntax of MMC programs, after type inference, is given by the following (incomplete) grammar:

\begin{align*}
  \alpha,x,h,k\in \mathrm{Ident} ::={}& \mathrm{identifiers}\\
  s \in \mathrm{Size} ::={}& 8\mid 16\mid 32\mid 64\mid \infty&&\mbox{integer bit size}\\
  t \in \mathrm{TuplePattern} ::={}& \_\mid x\mid \ghost{x}&&\mbox{ignored, variable, ghost variable}\\
    \mid{}&t:\tau \mid \langle \overline{t}\rangle&&\mbox{type ascription, tuple}\\
  R \in \mathrm{Arg} ::={}& x:\tau\mid \ghost{x}:\tau\mid h:A&&\mbox{regular/ghost/proof argument}\\
  \tau\in\mathrm{Type} ::={}& \alpha&&\mbox{type variable reference}\\
    \mid{}& \core\alpha&&\mbox{moved type variable}\\
    \mid{}&\mathbf{0}\mid \mathbf{1}\mid \mathsf{bool}&&\mbox{void, unit, booleans}\\
    \mid{}&\N_s\mid \Z_s&&\mbox{unsigned and signed integers of different sizes}\\
    \mid{}&\textstyle\bigcap\overline{\tau} \mid \textstyle\bigcup \overline{\tau}&&\mbox{intersection type, (undiscriminated) union type}\\
    \mid{}&\textstyle\Sep\overline{\tau} \mid \textstyle\sum\overline{R}&&\mbox{tuple type, structure (dependent tuple) type}\\
    \mid{}&S(\overline{\tau},\overline{pe})&&\mbox{user-defined type}\\
\end{align*}
\begin{align*}
  A\in\mathrm{Prop} ::={}& pe&&\mbox{assert that a boolean value is true}\\
    \mid{}&\top\mid \bot\mid \mathsf{emp}&&\mbox{true, false, empty heap}\\
    \mid{}&\forall x:\tau,\;A\mid \exists x:\tau,\;A&&\mbox{universal, existential quantification}\\
    \mid{}&A_1\to A_2\mid \neg A&&\mbox{implication, negation}\\
    \mid{}&A_1\land A_2\mid A_1\lor A_2&&\mbox{conjunction, disjunction}\\
    \mid{}&A_1\ast A_2\mid A_1 \wand A_2&&\mbox{separating conjunction and implication}\\
    \mid{}&pe\mapsto pe'&&\mbox{points-to assertion}\\
    \mid{}&\boxed{x:\tau}&&\mbox{typing assertion}\\
\end{align*}
\begin{align*}
  pe\in \mathrm{PureExpr} ::={}&\mbox{(the first half of Expr below)}&&\mbox{pure expressions}\\
  e \in \mathrm{Expr} ::={}& x&&\mbox{variable reference}\\
    \mid{}&()\mid \mathsf{true}\mid \mathsf{false}\mid n&&\mbox{constants}\\
    \mid{}&e_1 \land e_2\mid e_1 \lor e_2\mid \neg e&&\mbox{logical AND, OR, NOT}\\
    \mid{}&e_1 \mathbin\texttt{\&} e_2\mid e_1 \mathbin\texttt{|} e_2\mid \texttt{!}_s\; e&&\mbox{bitwise AND, OR, NOT}\\
    \mid{}&e_1 + e_2\mid e_1 * e_2\mid -e&&\mbox{addition, multiplication, negation}\\
    \mid{}&e_1 < e_2\mid e_1 \le e_2\mid e_1 = e_2&&\mbox{equalities and inequalities}\\
    \mid{}&\mathsf{if}\;h^? : e_1\;\mathsf{then}\;e_2\;\mathsf{else}\;e_3&&\mbox{conditionals}\\
    \mid{}&\langle\overline{e}\rangle&&\mbox{tuple}\\
    \mid{}&f(\overline{e})&&\mbox{(pure) function call}\\[2mm]
%
    \mid{}&\mathsf{let}\ h^? := t := e_1\;\mathsf{in}\; e_2 &&\mbox{assignment to a regular variable}\\
    \mid{}& \mathsf{let}\ t := p\;\mathsf{in}\; e&&\mbox{assignment to a hypothesis}\\
    \mid{}& \eta \gets pe;\ e&&\mbox{move assignment}\\
    \mid{}&F(\overline{e})&&\mbox{procedure call}\\
    \mid{}&\mathsf{unreachable}\;p&&\mbox{unreachable statement}\\
    \mid{}&\mathsf{return}\; \overline{e}&&\mbox{procedure return}\\
    \mid{}&\mathsf{label}\;\overline{k(\overline{R}):=e}\;\mathsf{in}\;e'&&\mbox{local mutual tail recursion}\\
    \mid{}&\mathsf{goto}\;k(\overline{e})&&\mbox{local tail call}\\
  \eta \in \mathrm{Place} ::={}& x&&\mbox{variable reference}\\
\end{align*}
\begin{align*}
  p \in \mathrm{Proof} ::={}&\mathsf{entail}\;\overline{p}\;q&&\mbox{entailment proof}\\
    \mid{}&\mathsf{assert}\;pe&&\mbox{assertion}\\
    \mid{}&\mathsf{typeof}\;pe&&\mbox{take the type of a variable}\\
  q \in \mathrm{PureProof} ::={}&\dots&&\mbox{MM0 proofs}\\
  it \in \mathrm{Item} ::={}&\mathsf{type}\;S(\overline{\alpha}, \overline{R}):=\tau&&\mbox{type declaration}\\
    \mid{}&\mathsf{const}\;t:=e&&\mbox{constant declaration}\\
    \mid{}&\mathsf{global}\;t:=e&&\mbox{global variable declaration}\\
    \mid{}&\mathsf{func}\;f(\overline{R}):\overline{R}:=e&&\mbox{function declaration}\\
    \mid{}&\mathsf{proc}\;f(\overline{R}):\overline{R}:=e&&\mbox{procedure declaration}\\
\end{align*}

Missing elements of the grammar include:
\begin{itemize}
  \item Switch statements, which are desugared to if statements.
  \item Raw MM0 formulas can be lifted to the `Prop' type.
  \item Raw MM0 values can be lifted into $\N_\infty$ and $\Z_\infty$.
  \item There are more operations for working with pointers and arrays. These are discussed in section \ref{sec:pointers}.
  \item There are operations for moving between typed values and hypotheses, which will be discussed later.
  \item There are also \textsf{while} loops and \textsf{for} loops, but we will focus on the general control flow of \textsf{label} and \textsf{goto}.
\end{itemize}

Language items that are considered but not present (yet) in the language include:
\begin{itemize}
  \item Functions and procedures cannot be generic over type and propositional variables. (In fact there are no propositional variables in the language, only the type Prop of propositional expressions.) A generic propositional variable is used internally to model the frame rule but it is not available to user code.
  \item Recursive and mutually recursive function support is currently very limited.
\end{itemize}
Most of the constructs are likely familiar from other languages. We will call some attention to the more unusual features:
\begin{itemize}
  \item Ghost variables $\ghost x$ are used to represent computationally irrelevant data. They can be manipulated just like regular variables, but they must not appear on the data path during code generation. We will use $x^\gamma$ to generalize over ghost and non-ghost variables, where $\gamma=\bot$ means this is a ghost variable and $\gamma=\top$ means it is not. We use $\gamma'\le \gamma$ to mean that $\gamma$ is ``more computationally relevant'' than $\gamma'$, i.e. if $x^\gamma$ is ghost then $x^{\gamma'}$ is too.

  \item The $\texttt{!}_s\; n$ operation performs the mathematical function $2^s-n-1$, taking $2^\infty=0$ so that $\texttt{!}_\infty\; n=-n-1$. $\texttt{!}_s\; n$ is used for bitwise negation of unsigned integers, and $\texttt{!}_\infty\; n$ is used for bitwise negation of signed integers (even those of finite width).
  \item The assignment operator $\mathsf{let}\ h^? := t := e_1\;\mathsf{in}\; e_2$ assigns the variables of $t$ to the result of $e_1$, but here it should be understood as a new binding, or shadowing declaration, rather than a reassignment to an existing variable. Even array assignments will be desugared into pure-functional update operations.

  Here $h^?$ denotes that the hypothesis binding $h$ is optional; we will write the version with no hypothesis binding as $\mathsf{let}\ t := e_1\;\mathsf{in}\; e_2$. The version that has a hypothesis binding requires that $e_1$ is pure.

  The concrete version of the assignment operator also contains a ``$\mathsf{with}\ x\to y$'' clause, but this only renames variables in the source (which is to say, it changes the mapping of source names to internal names) and so is not relevant for the theoretical presentation here.

  \item The operator $x\gets pe;\ e$ is the primitive for mutation of the variables in the context. Intuitively, it can be thought as moving $pe$ into $x$, but it has no effect on the type context, and is only used to coordinate data flow. In the grammar the left hand side is generalized to a type of ``places'' (a.k.a lvalues), but for now these can only be variable references. For example,
  \begin{align*}
    &\qquad\mbox{this:}
      &&\!\!\!\!\!\!\mbox{has the same effect as:}
        &&\!\!\!\!\!\!\mbox{which we can $\alpha$-rename to:}\\
    &\mathsf{let}\ x := 1\;\mathsf{in}
      &&\mathsf{let}\ x := 1\;\mathsf{in}
        &&\mathsf{let}\ x := 1\;\mathsf{in}\\
    &\mathsf{let}\ y :=
      &&\mathsf{let}\ \langle x,y\rangle :=
        &&\mathsf{let}\ \langle x',y\rangle :=\\
    &\quad x \gets x+1;
      &&\quad \mathsf{let}\ x := x+1\;\mathsf{in}\;
        &&\quad \mathsf{let}\ x' := x+1\;\mathsf{in}\;\\
    &\quad {-x}\;\mathsf{in}
      &&\quad \langle x,-x\rangle\;\mathsf{in}
        &&\quad \langle x',-x'\rangle\;\mathsf{in}\\
    &e(x,y)
      &&e(x,y)
        &&e(x',y)
  \end{align*}

  The surface syntax uses a combination of $\mathsf{mut}$ declarations and shadowing let bindings to signal that a move assignment is desired; $\mathsf{move}$ is the desugared form.
  One can view this as one part of a phi expression in SSA form.

  \item The expression $\mathsf{label}\;\overline{k(\overline{R}):=e}\;\mathsf{in}\;e'$ is similar in behavior to a recursive let binding such as those found in functional languages, but the $\overline{k}$ are all continuations, which is to say they do not return to the caller when using $\mathsf{goto}\;l(\overline{e})$, which is how we ensure that they can be compiled to plain $\mathsf{label}$ and $\mathsf{goto}$ at the machine code level.

  \item The $\mathsf{typeof}\;pe$ operator ``moves'' a value $x:\tau$ and returns a fact $\boxed{x:\tau}$ that asserts ownership of the resources of $x$. See \ref{sec:moving}.
\end{itemize}

\section{Typing}

\subsection{Overview}

The main typing judgments are:

\begin{itemize}
  \item $\Gamma \proves t:\tau \Rightarrow \overline{R}$ and $\Gamma \proves t:A\Rightarrow \overline{R}$\\ type a tuple pattern against a value of type $\tau$ or $A$, producing additional hypotheses $\overline{R}$ that will enter the context
  \item $\Gamma \proves \tau\;\mathsf{type}$\\ determines that a type $\tau$ is a valid type in the current context
  \item $\Gamma \proves A\;\mathsf{prop}$\\ determines that $A$ is a valid separating proposition in the current context
  \item $\Gamma \proves R\;\mathsf{arg}$\\ determines that $R$ is a valid argument extending the current context
  \item $\Gamma \proves e:\tau \makes\Gamma'$\\ determines that $e$ is a valid expression of type $\tau$, which modifies the context to $\Gamma'$. In the special case where $\Gamma'=\Gamma$, we will write $\Gamma \proves e:\tau$ instead.
  \item $\Gamma \proves pe:\tau$\\ This is only a specialization of the $\Gamma \proves e:\tau$ judgment, because pure expressions do not change the context.
  \item $\Gamma \proves p:A \makes\Gamma'$\\ determines that $p$ is a proof of $A$, which modifies the context to $\Gamma'$. In the special case where $\Gamma'=\Gamma$, we will write $\Gamma \proves p:A$ instead.
  \item $\Gamma \constep \Gamma'$\\ an auxiliary judgment for applying pending mutations to the context.
  \item $\Gamma \proves e:\tau\makesto\Gamma'$ is defined to mean $\Gamma \proves e:\tau\makes\Gamma_1\ \wedge\ \Gamma_1\constep\Gamma'$ for some $\Gamma_1$.
  \item $\Gamma\proves it\;\mathsf{ok}$\\ The top level item typing judgment
\end{itemize}

Central to all of these judgments is the context $\Gamma$, which consists of:
\begin{itemize}
  \item The global environment of previously declared items, including in particular a record $\mathsf{self}(\bar R):\bar S$ recording the type of the function being typechecked (if a function/procedure is being checked). This doesn't change during expression typing.
  \item A list of type variables $\overline{\alpha}$. This is only nonempty when type checking a type declaration.
  \item A list of declared jump targets $\overline{k(\bar{R})}$, including a special jump target $\mathsf{return}(\bar{R})$ where $\bar{R}$ is the declared return type.
  \item A list of regular variables, ghost variables, and hypotheses $\overline{R}$ with their types.
  \item (Used only in non-pure expression and proofs:) An unordered map of mutation records of the form $x\gets pe:\tau$ where $x$ is already in the context and $\Gamma\proves pe:\tau$. These represent mutations to elements of the context that need to be propagated forward along the control flow.
\end{itemize}
The type variables don't depend on anything and cannot be introduced in the middle of an item, so these can be assumed to come first, but jump targets can depend on regular variables. We use the notation $\Gamma,\overline{k(\bar{R})}$ and $\Gamma,\overline{R}$ to denote extension of the context with a list of jump targets or variables, respectively, and $\Gamma,x\gets pe:\tau$ to denote the insertion of $x\gets pe:\tau$ into the list of mutations, replacing $x\gets pe':\tau'$ if it is present.

\subsection{Moving types}\label{sec:moving}

The last essential element to understand the typing rules is the ``moved'' modality on types and propositions, denoted $\core\tau$ or $\core A$. For separating propositions this is also known as the persistence modality, and it represents what is left of a proposition after all the ``ownership'' is removed from it. We use moved types to represent a value that has been accessed. This satisfies the axioms $\core{\core\tau}=\core\tau$ and $A\Leftrightarrow A\ast\core A$. We extend this to arbitrary arguments and contexts $\core R$ and $\core\Gamma$ by applying the modality to all contained types and propositions.

A type/proposition is called ``$\mathsf{copy}$'' or persistent if $\core\tau=\tau$, and is denoted $\tau\;\mathsf{copy}$.

The moved modality is defined like so:
\begin{align*}
  \core\alpha,\mathbf{0}, \mathbf{1}, \mathsf{bool},\N_s, \Z_s&\;\mathsf{copy}\\
  \core\alpha={}&\core\alpha\qquad\mbox{(that is, $\alpha$ maps to $\core\alpha$)}\\
  \core{\textstyle\bigcap\overline{\tau}}={}&\textstyle\bigcap\overline{\core\tau}\\
  \core{\textstyle\bigcup\overline{\tau}}={}&\textstyle\bigcup\overline{\core\tau}\\
  \core{\textstyle\Sep\overline{\tau}}={}&\textstyle\Sep\overline{\core\tau}\\
  \core{\textstyle\sum\overline{\tau}}={}&\textstyle\sum\overline{\core\tau}\\
  \core{S(\overline{\tau},\overline{pe})}={}&[S](\overline{\tau},\overline{pe})\qquad\mbox{(that is, the effect of moving $S$ is precalculated)}
\end{align*}
There are no interesting cases among the types presented here. When we get to pointer types in section \ref{sec:pointers} we will see that $\core{\&^\mathbf{own}\tau}=\core{\&^\mathbf{mut}\tau}=\N_{64}$, so pointers become ``mere integers'' after they are moved away. (Note, however, that they actually retain their original types for type inference purposes; that is, the typechecker remembers that they have type $\core{\&^\mathbf{own}\tau}$ in order to determine the type that would result from dereferencing the pointer, if it were still valid.)

For propositions, the effect is more dramatic:
\begin{align*}
  pe,\top,\bot,\mathsf{emp}&\;\mathsf{copy}\\
  \core{\forall x:\tau,\;A}={}& \begin{cases}
    \forall x:\tau,\;\core A&\mbox{if $\tau\;\mathsf{copy}$}\\
    \mathsf{emp}&o.w.\\
  \end{cases}\\
  \core{\exists x:\tau,\;A}={}&\exists x:\core\tau,\;\core A\\
  \core{A_1\land A_2}={}&\core{A_1}\land \core{A_2}\\
  \core{A_1\lor A_2}={}&\core{A_1}\lor \core{A_2}\\
  \core{A\to A'}={}& \begin{cases}
    A\to \core{A'}&\mbox{if $A\;\mathsf{copy}$}\\
    \mathsf{emp}&o.w.\\
  \end{cases}\\
  \core{\neg A}={}& \begin{cases}
    A&\mbox{if $A\;\mathsf{copy}$}\\
    \mathsf{emp}&o.w.\\
  \end{cases}\\
\end{align*}
\begin{align*}
  \core{A_1\ast A_2}={}&\core{A_1}\ast \core{A_2}\\
  \core{A\wand A'}={}& \begin{cases}
    A\wand \core{A'}&\mbox{if $A\;\mathsf{copy}$}\\
    \mathsf{emp}&o.w.\\
  \end{cases}\\
  \core{pe\mapsto pe'}={}&\mathsf{emp}\\
  \core{\boxed{x:A}}={}&\boxed{x:\core{A}}\\
\end{align*}
Because moving is monotonic, that is $A\to \core A$ but not the other way around, negative uses of a non-persistent proposition cause it to completely collapse to \textsf{emp} when moved.

\subsection{The Typing Rules}

We now give the main typing rules for the logic. This corresponds roughly to the \texttt{typeck} phase of the compiler. Note that ghost variable markings are ignored during this phase; they will come back during the layout phase.

\judgmentB[Tuple pattern typing]{\Gamma \proves t:\tau \Rightarrow \overline{R}}{\Gamma \proves t:A \Rightarrow \overline{R}}
\begin{mathparpagebreakable}
  \axiom[tpt-ignore]{\Gamma \proves \_:\tau\Rightarrow \cdot}\and
  \axiom[tpp-ignore]{\Gamma \proves \_:A\Rightarrow \cdot}\and
  \axiom[tpt-var]{\Gamma \proves x^\gamma:\tau\Rightarrow x^\gamma:\tau}\and
  \axiom[tpp-var]{\Gamma \proves h:A\Rightarrow h:A}\and
  \infer[tpt-typed]
    {\Gamma \proves t:\tau\Rightarrow \overline{R}}
    {\Gamma \proves (t:\tau):\tau\Rightarrow \overline{R}}\and
  \infer[tpp-typed]
    {\Gamma \proves t:A\Rightarrow \overline{R}}
    {\Gamma \proves (t:A):A\Rightarrow \overline{R}}\and
  \infer[tpt-sum]
    {\Gamma \proves t:\textstyle \tau\Rightarrow \bar{S}\quad
      \Gamma,\bar{S} \proves \langle \overline{t'}\rangle:\textstyle \overline{R}[t/x]\Rightarrow \bar{S}'}
    {\Gamma \proves \langle t,\overline{t'}\rangle:\textstyle\sum x:\tau,\overline{R}\Rightarrow \bar{S},\bar{S}'}\and
  \infer[tpp-ex]
    {\Gamma \proves t:\textstyle \tau\Rightarrow \bar{S}\quad
      \Gamma,\bar{S} \proves \langle \overline{t'}\rangle:\textstyle \overline{R}[t/x]\Rightarrow \bar{S}'}
    {\Gamma,\bar{S} \proves \langle t,\overline{t'}\rangle:\textstyle\exists x:\tau,\overline{R}\Rightarrow \bar{S},\bar{S}'}\and
  \infer[tpt-list]
    {\forall i,\ \ \Gamma \proves t_i:\tau_i\Rightarrow(\bar{R})_i}
    {\Gamma \proves \langle \overline{t}\rangle:\textstyle\Sep\overline{\tau}\Rightarrow \overline{\bar{R}}}\and
  \infer[tpt-and]
    {\forall i,\ \tau_i\;\mathsf{copy}\quad
      \forall i,\ \Gamma \proves t_i:\tau_i\Rightarrow(\bar{R})_i}
    {\Gamma \proves \langle \overline{t}\rangle:\textstyle\bigwedge\overline{\tau}\Rightarrow \overline{\bar{R}}}\and
  \infer[tpp-sep]
    {\Gamma \proves t:\textstyle A\Rightarrow \bar{R}\quad
      \Gamma \proves t':\textstyle A'\Rightarrow \bar{R}'}
    {\Gamma \proves \langle t,t'\rangle:A\ast A'\Rightarrow \bar{R},\bar{R}'}\and
  \infer[tpp-and]
    {\Gamma \proves t:\textstyle A\Rightarrow \bar{R}\quad
      \Gamma \proves t':\textstyle \core{A'}\Rightarrow \bar{R}'}
    {\Gamma \proves \langle t,t'\rangle:A\land A'\Rightarrow \bar{R},\bar{R}'}\and
\end{mathparpagebreakable}

The only really relevant rules here for expressiveness are the \textsc{tpt-var} and \textsc{tpp-var} rules; the rest are convenience rules for being able to destructure a type or proposition into components using the tuple pattern. For notational simplicity we show the \textsc{tpt-sum} rule in iterative form, but it actually matches an $n$-ary tuple against an $n$-ary struct type in one go.

In the \textsc{tpt-sum} and \textsc{tpp-ex} rules, we use $\overline{R}[t/x]$ to denote the result of substituting $t$ for $x$ in $R$. For this to work, $t$ must be reified as a tuple of variables rather than simply a destructuring pattern, which in particular means that `$\_$' ignore patterns are interpreted as inserting internal variables with no user-specified name rather than being omitted from the context entirely as the \textsc{tpt-ignore} rule would suggest.

\judgment[Argument typing]{\Gamma \proves R\;\mathsf{arg}}
\begin{mathparpagebreakable}
  \infer[arg-type]
    {\Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves x^\gamma:\tau\;\mathsf{arg}}\and
  \infer[arg-prop]
    {\Gamma \proves A\;\mathsf{prop}}
    {\Gamma \proves h:A\;\mathsf{arg}}\and
\end{mathparpagebreakable}
This one is simple so we get it out of the way first. We will avoid dealing with variable shadowing rules here; suffice it to say that variables in the context must always be distinct, and we will perform renaming from the surface syntax to ensure this property when necessary. Also remember that $x^\gamma$ represents either $x$ or $\ghost x$ in this rule.

\judgment[Type validity]{\Gamma \proves \tau\;\mathsf{type}}
\begin{mathparpagebreakable}
  \axiom[ty-void]{\Gamma \proves \mathbf{0}\;\mathsf{type}}\and
  \axiom[ty-unit]{\Gamma \proves \mathbf{1}\;\mathsf{type}}\and
  \axiom[ty-bool]{\Gamma \proves \mathsf{bool}\;\mathsf{type}}\and
  \axiom[ty-nat]{\Gamma \proves \N_s\;\mathsf{type}}\and
  \axiom[ty-int]{\Gamma \proves \Z_s\;\mathsf{type}}\\
  \infer[ty-var]
    {\alpha\in\Gamma}
    {\Gamma \proves \alpha\;\mathsf{type}}\and
  \infer[ty-core-var]
    {\alpha\in\Gamma}
    {\Gamma \proves \core\alpha\;\mathsf{type}}\and
  \infer[ty-inter]
    {\forall i,\ \ \Gamma \proves \tau_i\;\mathsf{type}}
    {\Gamma \proves \textstyle\bigcap\tau\;\mathsf{type}}\and
  \infer[ty-union]
    {\forall i,\ \ \Gamma \proves \tau_i\;\mathsf{type}}
    {\Gamma \proves \textstyle\bigcup\tau\;\mathsf{type}}\and
  \infer[ty-list]
    {\forall i,\ \ \Gamma \proves \tau_i\;\mathsf{type}}
    {\Gamma \proves \textstyle\Sep\tau\;\mathsf{type}}\and
  \infer[ty-struct-1]
    {\Gamma \proves R_0\;\mathsf{arg}}
    {\Gamma \proves \textstyle\sum R_0\;\mathsf{type}}\and
  \infer[ty-struct-2]
    {\Gamma \proves R_0\;\mathsf{arg}\quad
      \Gamma, R_0 \proves \textstyle\sum\overline{R}\;\mathsf{type}}
    {\Gamma \proves \textstyle\sum R_0,\overline{R}\;\mathsf{type}}\and
  \infer[ty-user]
    {\mathsf{type}\;S(\overline{\alpha}, \overline{R})\quad
      \forall i,\ \Gamma \proves \tau_i\;\mathsf{type}\quad
      \Gamma \proves \langle \overline{pe}\rangle:\textstyle\sum\overline{R}[\overline{\tau}/\overline{\alpha}]}
    {\Gamma \proves S(\overline{\tau},\overline{pe})\;\mathsf{type}}\and
\end{mathparpagebreakable}

Type validity is also relatively straightforward. Type variables are looked up in the context, and structs can have dependent types, but the only way dependencies can appear is through \textsc{ty-array}, which can have a natural number size bound, and in hypotheses that appear in struct declarations.

\judgment[Proposition validity]{\Gamma \proves A\;\mathsf{prop}}
\begin{mathparpagebreakable}
  \axiom[typ-true]{\Gamma \proves \top\;\mathsf{prop}}\and
  \axiom[typ-false]{\Gamma \proves \bot\;\mathsf{prop}}\and
  \axiom[typ-emp]{\Gamma \proves \mathsf{emp}\;\mathsf{prop}}\and
  \infer[typ-bool]
    {\Gamma \proves pe:\mathsf{bool}}
    {\Gamma \proves pe\;\mathsf{prop}}\and
  \infer[typ-not]
    {\Gamma \proves A\;\mathsf{prop}}
    {\Gamma \proves \neg A\;\mathsf{prop}}\and
  \infer[typ-and]
    {\Gamma \proves A\;\mathsf{prop}\and
      \Gamma \proves B\;\mathsf{prop}}
    {\Gamma \proves A\land B\;\mathsf{prop}}\and
  \infer[typ-or]
    {\Gamma \proves A\;\mathsf{prop}\and
      \Gamma \proves B\;\mathsf{prop}}
    {\Gamma \proves A\lor B\;\mathsf{prop}}\and
  \infer[typ-sep]
    {\Gamma \proves A\;\mathsf{prop}\and
      \Gamma \proves B\;\mathsf{prop}}
    {\Gamma \proves A\ast B\;\mathsf{prop}}\and
  \infer[typ-wand]
    {\Gamma \proves A\;\mathsf{prop}\and
      \Gamma \proves B\;\mathsf{prop}}
    {\Gamma \proves A\wand B\;\mathsf{prop}}\and
  \infer[typ-forall]
    {\Gamma \proves \tau\;\mathsf{type}\quad
      \Gamma,x:\core\tau \proves A\;\mathsf{prop}}
    {\Gamma \proves \forall x:\tau,\;A\;\mathsf{prop}}\and
  \infer[typ-exists]
    {\Gamma \proves \tau\;\mathsf{type}\quad
      \Gamma,x:\core\tau \proves A\;\mathsf{prop}}
    {\Gamma \proves \exists x:\tau,\;A\;\mathsf{prop}}\and
  \infer[typ-points-to]
    {\Gamma \proves \ell:\mathsf{\N_{64}}\quad
      \Gamma \proves v:\mathsf{\core\tau}}
    {\Gamma \proves \ell\mapsto v\;\mathsf{prop}}\and
  \infer[typ-typing]
    {\Gamma \proves x:\core\tau\quad
      \Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves \boxed{x:\tau}\;\mathsf{prop}}\and
\end{mathparpagebreakable}

There is nothing non-standard in these rules, except perhaps the requirement in the \textsc{typ-forall} and \textsc{typ-exists} rules that the types are moved (needed because the assertion language itself should not be able to take ownership of variables used in the assertions).

The most interesting rule is \textsc{typ-typing}, which describes the typing assertion $\boxed{x:\tau}$. One should think of $x:\tau$ in the context as a separating conjunction of $x:\core\tau$ (which asserts, roughly, that $x$ is a reference to some data in the stack frame that is a valid bit-pattern for type $\tau$), plus the ``fact'' $h:\boxed{x:\tau}$, which represents ownership of all the resources that $x$ may point to. For example, if $x:\&^\mathbf{own}\tau$, then $x$ is itself just a number, but $\boxed{x:\&^\mathbf{own}\tau}$ is equal to $\exists v:\tau,\ x\mapsto v$, saying that $x$ points to some data $v$, and $v:\tau$ may itself own some portion of the heap.

\subsection{Expression typing}

The typing rules for expressions make use of the following operators on contexts:

\begin{itemize}
  \item $\Gamma_{\core x}$ ``moves'' $x$ out of the context, by replacing $x:\tau$ with $x:\core\tau$ or $x:A$ with $x:\core A$. This does not invalidate the well formedness of any type, proposition, or pure expression.
\end{itemize}

The rules for pure expression typing are the same as for regular expression typing, although since all the pure expression constructors do not change the context, they are all of the form $\Gamma\vdash pe:\tau\makes \Gamma$, which we abbreviate as $\Gamma\vdash pe:\tau$.

Note that the \textsc{tye-var-ref} rule ignores the effect of mutations. This is necessary so that new mutations do not cause the context to become ill-typed. Instead, mutations are applied in the translation from surface syntax, so that ``$x\gets 1;\ x+x$'' is elaborated into ``$\mathsf{move}\;x\gets 1\;\mathsf{in}\;1+1$''.

\judgment[Expression validity (pure expressions)]{\Gamma \proves e:\tau\makes\Gamma'}
\begin{mathparpagebreakable}
  \infer[tye-var-ref]
    {(x^\gamma:\tau)\in\Gamma}
    {\Gamma \proves x:\core\tau}\and
  \axiom[tye-unit]{\Gamma \proves ():\mathbf{1}}\and
  \axiom[tye-true]{\Gamma \proves \mathsf{true}:\mathsf{bool}}\and
  \axiom[tye-false]{\Gamma \proves \mathsf{false}:\mathsf{bool}}\and
  \infer[tye-nat]
    {0\le n\quad s<\infty\to n<2^s}
    {\Gamma \proves n:\N_s}\and
  \infer[tye-int]
    {s<\infty\to -2^{s-1}\le n<2^{s-1}}
    {\Gamma \proves n:\Z_s}\and
  \infer[tye-tuple]
    {\forall i<n,\ \ \Gamma_i \proves e_i:\tau\makes\Gamma_{i+1}}
    {\Gamma_0 \proves \langle\overline{e}\rangle:\textstyle\Sep\tau\makes\Gamma_n}\and
  \infer[tye-not]
    {\Gamma \proves e:\mathsf{bool}\makes\Gamma'}
    {\Gamma \proves \neg e:\mathsf{bool}\makes\Gamma'}\and
  \infer[tye-and, tye-or]
    {\Gamma \proves e_1:\mathsf{bool}\makes\Gamma_1\quad
      \Gamma_1 \proves e_2:\mathsf{bool}\makes\Gamma_2}
    {\Gamma \proves e_1\land e_2:\mathsf{bool}\makes\Gamma_2 \quad
      \Gamma \proves e_1\lor e_2:\mathsf{bool}\makes\Gamma_2}\and
  \infer[tye-band, tye-bor]
    {\tau\in\{\N_s,\Z_s\}\quad
      \Gamma \proves e_1:\tau\makes\Gamma_1\quad
      \Gamma_1 \proves e_2:\tau\makes\Gamma_2}
    {\Gamma \proves e_1\mathrel{\texttt{\&}} e_2:\tau\makes\Gamma_2 \quad
      \Gamma \proves e_1\mathrel{\texttt{|}} e_2:\tau\makes\Gamma_2}\and
  \infer[tye-bnot]
    {\tau=\N_s\lor (\tau=\Z_{s'}\land s=\infty)\quad
      \Gamma \proves e:\tau\makes\Gamma'}
    {\Gamma \proves \texttt{!}_s\;e:\tau\makes\Gamma'}\and
  \infer[tye-lt, tye-le, tye-eq]
    {\tau,\tau'\in\{\N_s,\Z_s\}\qquad
      \Gamma \proves e_1:\tau\makes\Gamma_1\qquad
      \Gamma_1 \proves e_2:\tau'\makes\Gamma_2}
    {\Gamma \proves e_1< e_2:\mathsf{bool}\makes\Gamma_2\quad
      \Gamma \proves e_1\le e_2:\mathsf{bool}\makes\Gamma_2\quad
      \Gamma \proves e_1= e_2:\mathsf{bool}\makes\Gamma_2}\and
  \infer[tye-dep-if]
    {c\ \mbox{pure}\quad \Gamma \proves c:\mathsf{bool}\quad
      \Gamma,h:c \proves e_1:\tau\makesto\Gamma',h:c\quad
      \Gamma,h:\neg c \proves e_2:\tau\makesto\Gamma',h:\neg c}
    {\Gamma \proves (\mathsf{if}\;h : c\;\mathsf{then}\;e_1\;\mathsf{else}\;e_2):\tau\makes\Gamma'}\and
  \infer[tye-if]
    {\Gamma \proves c:\mathsf{bool}\makes\Gamma'\quad
      \Gamma' \proves e_1:\tau\makesto\Gamma''\quad
      \Gamma' \proves e_2:\tau\makesto\Gamma''}
    {\Gamma \proves (\mathsf{if}\;c\;\mathsf{then}\;e_1\;\mathsf{else}\;e_2):\tau\makes\Gamma''}\and
  \infer[tye-struct-var\footnotemark]
    {\Gamma_0 \proves e:\tau\makes\Gamma_1\quad
      \Gamma_1 \proves \langle \overline{e}\rangle:\textstyle\sum \bar R[e/x]\makes\Gamma_n}
    {\Gamma_0 \proves \langle e,\overline{e}\rangle:\textstyle\sum x^\gamma:\tau,\bar R\makes\Gamma_n}\and
  \footnotetext{In \textsc{tye-struct-var}, $e$ must be pure or $x\notin\mathrm{Var}(\bar R)$, so that $\bar R[e/x]$ is well defined.}
  \infer[tye-struct-prop]
    {\Gamma_0 \proves p:A\makes\Gamma_1\quad
      \Gamma_1\proves \langle \overline{e}\rangle:\textstyle\sum \bar R\makes\Gamma_n}
    {\Gamma_0 \proves \langle p,\overline{e}\rangle:\textstyle\sum h:A,\bar R\makes\Gamma_n}\and
  \infer[tye-func-call]
    {\mathsf{func}\;f(\overline{R}):\overline{S}\quad
      \Gamma \proves \langle\overline{e}\rangle:\textstyle\sum\bar R\makes\Gamma'}
    {\Gamma \proves f(\overline{e}):\textstyle\sum\bar S\makes\Gamma'}\and
\end{mathparpagebreakable}

The rules above are the only ones that apply to pure expressions. General expressions have additional typing rules for the other constructions, continued below.

For general expressions, we must worry about the following additional effects:
\begin{itemize}
  \item Variables in the context can be moved by their being referenced (in the \textsc{tye-var-move} rule).
  \item Variables can be mutated, resulting in contexts with unapplied mutations. We will return to this in section \ref{sec:mutapp}.
\end{itemize}

\judgment[Expression validity]{\Gamma \proves e:\tau\makes\Gamma'}
\begin{mathparpagebreakable}
  \infer[tye-var-move]
    {(x^\gamma:\tau)\in\Gamma}
    {\Gamma \proves x:\tau\makes\Gamma_{|x|}}\and
  \infer[tye-mut]
    {\!\:{\Gamma \proves pe:\tau\makes\Gamma'\qquad
      (x^\gamma:\tau'')\in\Gamma'\atop
      \Gamma',x\gets pe:\tau\proves e:\tau'\makes\Gamma''}}
    {\Gamma \proves (x\gets pe;\ e):\tau'\makes\Gamma''}\and
  \infer[tye-mut-pr]
    {\!\:{\Gamma \proves p:A\makes\Gamma'\qquad
      (h:A')\in\Gamma'\atop
      \Gamma',h\gets p:A\proves e:\tau\makes\Gamma''}}
    {\Gamma \proves (h\gets p;\ e):\tau\makes\Gamma''}\and
  \infer[tye-let-hyp\footnotemark]
    {\!\:{\Gamma \proves pe:\tau\qquad
      \Gamma \proves t:\tau\Rightarrow \overline{R}\qquad
      \Gamma' \proves \tau'\;\mathsf{type}\atop
      \Gamma,\overline{R},h:t=pe \proves e:\tau'\makesto\Gamma',\overline{R},h:t=pe}}
    {\Gamma \proves (\mathsf{let}\ h := t := pe\;\mathsf{in}\; e):\tau'\makes\Gamma'}\and
  \footnotetext{In \textsc{tye-let-hyp}, $t$ must not contain ignore patterns so that $t$ is a pure expression and $t=pe$ is well defined.}
  \infer[tye-unreachable]
    {\Gamma \proves p:\bot\makes\Gamma'}
    {\Gamma \proves \mathsf{unreachable}\;p:\tau}\and
  \infer[tye-let]
    {\!\:{\Gamma \proves e_1:\tau\makes \Gamma'\quad
      \Gamma' \proves t:\tau\Rightarrow \overline{R}\quad
      \Gamma'' \proves \tau'\;\mathsf{type}\atop
      \Gamma',\overline{R} \proves e_2:\tau'\makesto\Gamma'',\overline{R}}}
    {\Gamma \proves (\mathsf{let}\ t := e_1\;\mathsf{in}\; e_2):\tau'\makes\Gamma''}\and
  \infer[tye-proc-call]
    {\mathsf{proc}\;F(\overline{R}):\overline{S}\quad
      \Gamma \proves \langle\overline{e}\rangle:\textstyle\sum\bar R\makes\Gamma'}
    {\Gamma \proves F(\overline{e}):\textstyle\sum\bar S\makes\Gamma'}\and
  \infer[tye-let-pr]
    {\!\:{\Gamma \proves p:A\makes \Gamma'\quad
      \Gamma' \proves t:A\Rightarrow \overline{R}\quad
      \Gamma'' \proves t:\tau\;\mathsf{type}\atop
      \Gamma',\overline{R} \proves e:\tau\makesto\Gamma'',\overline{R}}}
    {\Gamma \proves (\mathsf{let}\ t := p\;\mathsf{in}\; e):\tau\makes\Gamma''}\and
  \infer[tye-return]
    {\mathsf{self}(\bar R):\bar S\quad
      \Gamma \proves \langle\overline{e}\rangle:\textstyle\sum\bar S\makesto \core{\bar R}}
    {\Gamma \proves \mathsf{return}\;\overline{e}:\tau}\and
  \infer[tye-label]
    {\forall i,\ \core{\Gamma},\overline{k(\bar{R})},(\bar{R})_i \proves e_i:\mathbf{0}\makes\Gamma''_i\quad
      \Gamma,\overline{k(\bar{R})}\proves e':\tau\makes\Gamma'}
    {\Gamma \proves (\mathsf{label}\;\overline{k(\bar{R}):=e}\;\mathsf{in}\;e'):\tau\makes\Gamma'}\and
  \infer[tye-goto]
    {\Gamma \proves \langle\overline{e}\rangle:\textstyle\sum(\bar R)_i\makesto \Gamma',\overline{k(\bar{R})}}
    {\Gamma \proves \mathsf{goto}\;k_i(\overline{e}):\tau}\and
\end{mathparpagebreakable}

Note that the \textsf{unreachable}, \textsf{return}, \textsf{goto} functions do not return to the calling context, so they return an arbitrary type $\tau$, and also roll back the context to the initial state $\Gamma$. A more complex model here would allow the final context to be a special context $\Gamma_\bot$, which can step to any context with the same variables as $\Gamma$.

Proofs are essentially (effectful) expressions with proposition type, so the rules look much the same. Pure proofs are simply imported from the MM0 logical enironment so we do not discuss them here. The main job of metamath C is to make sure that these pure proofs have simple types, not using the entire context, since the user will be directly interacting with them.

\judgment[Proof validity]{\Gamma \proves p:A\makes\Gamma'}
\begin{mathparpagebreakable}
  \infer[tpr-assert]
    {\Gamma \proves pe:\mathsf{bool} \makes \Gamma'}
    {\Gamma \proves \mathsf{assert}\;pe:pe\makes\Gamma'}\and
  \infer[tpr-typeof]
    {\Gamma \proves pe:\tau \makes \Gamma'}
    {\Gamma \proves \mathsf{typeof}\;pe:\boxed{pe:\tau}\makes\Gamma'}\and
  \infer[tpr-entail]
    {\Gamma \proves \langle\overline{p}\rangle:\textstyle\Sep\overline{A} \makes \Gamma'\quad
      \vdash q:\textstyle\Sep\overline{A}\wand B}
    {\Gamma \proves \mathsf{entail}\;\overline{p}\;q:B\makes\Gamma'}\and
\end{mathparpagebreakable}

\subsection{Mutation application}\label{sec:mutapp}

The role of the $\Gamma\proves e:\tau\makesto\Gamma'$ judgment is to clean up the context at the terminator of a basic block in the control flow graph: after the branches of an \textsf{if} statement, and at a \textsf{return} and \textsf{goto}. It is also used whenever the context has to drop a variable, such as after a $\mathsf{let}$ expression completes.

Recall that $\Gamma\proves e:\tau\makesto\Gamma'$ means $\Gamma\proves e:\tau\makes\Gamma_1$ and $\Gamma_1\constep\Gamma'$ for some $\Gamma_1$. The reason we can't just use $\Gamma_1$ directly is because there may be pending mutations, whose values depend on variables we are about to drop. But mutations to variables are not required to be well typed at the target variable at the time of mutation, because for example structs may be written incrementally, with the half written structs being ill-typed. Instead, we delay committing these values as long as possible, even across CFG edges if we can. However, the rules given below are not deterministic, because \textsc{cs-mut} steps can choose to apply any subset of outstanding mutations that are collectively well typed.

\judgment[Mutation application]{\Gamma \constep\Gamma'}
\begin{mathparpagebreakable}
  \axiom[cs-refl]{\Gamma \constep \Gamma}\and
  \infer[cs-trans]
    {\Gamma_1 \constep \Gamma_2 \quad \Gamma_2 \constep \Gamma_3}
    {\Gamma_1 \constep \Gamma_3}\and
  \infer[cs-drop]
    {\mbox{for all $S$, if $(x\gets S)\in\Gamma$ then $\Gamma\vdash S$}}
    {\Gamma,\overline{R}\constep\Gamma}\and
  \axiom[cs-drop-label]{\Gamma,\overline{k(\bar R)}\constep\Gamma}\and
  \infer[cs-move]
    {R\in \Gamma}
    {\Gamma \constep\Gamma_{|R|}}\and
  \infer[cs-mut]
    {\Gamma \proves \langle \overline{x}\rangle:\textstyle\sum\core{\overline{R}}\quad
      \Gamma \proves \langle \overline{e}\rangle:\textstyle\sum\overline{R}}
    {\Gamma,\overline{x\gets e} \constep\Gamma_{\overline{R}}}\and
\end{mathparpagebreakable}
Here $\Gamma_{|R|}$ is the context in which $R$ has been moved away to nowhere (i.e. the memory is released), and $\Gamma_{\bar R}$ is the context which restores each variable in $\bar R$ to the specified status, reflecting that they are no longer moved away after the resource is transferred into the context.

To see how this plays out, recall the \textsc{tye-return} rule:

$$\infer[tye-return]
    {\mathsf{self}(\bar R):\bar S\quad
      \Gamma \proves \langle\overline{e}\rangle:\textstyle\sum\bar S\makesto \core{\bar R}}
    {\Gamma \proves \mathsf{return}\;\overline{e}:\tau}$$

After executing $\langle\overline{e}\rangle$, we obtain the return value $\sum\bar S$ in some context $\Gamma'$. This context contains the same variables as $\Gamma$, but we are executing a return statement somewere deep in the function, so $\Gamma$ will typically contain many variables that were not parameters to the function (the list $\bar R$), and these variables may appear in uncommitted mutations that are still in $\Gamma$, so to ensure consistency of the state at the return of the function, we have to commit all outstanding mutations, expressed here by saying that the final state is simply $\core{\bar R}$, the moved-out version of the original context, with all extra variables and labels dropped, and no active mutations.

\subsection{Top level typing}

The full program consists of a list of top level items, which are typechecked incrementally:

\judgment[AST typing]{\Gamma\proves \overline{it}\makes \Gamma'}
\begin{mathparpagebreakable}
  \axiom[ok-zero]{\Gamma\proves \cdot\makes \Gamma}\and
  \infer[ok-append]
    {\Gamma\proves \overline{it}\makes \Gamma'\quad
      \Gamma'\vdash it\makes \Gamma''}
    {\Gamma\proves \overline{it},it'\makes \Gamma''}\and
\end{mathparpagebreakable}
Individual items are typed as follows:
% it \in \mathrm{Item} ::={}&\mathsf{type}\;S(\overline{\alpha}, \overline{R}):=\tau&&\mbox{type declaration}\\
% \mid{}&\mathsf{const}\;t:=e&&\mbox{constant declaration}\\
% \mid{}&\mathsf{global}\;t:=e&&\mbox{global variable declaration}\\
% \mid{}&\mathsf{func}\;f(\overline{R}):\overline{R}:=e&&\mbox{function declaration}\\
% \mid{}&\mathsf{proc}\;f(\overline{R}):\overline{R}:=e&&\mbox{procedure declaration}\\

\judgment[Item typing]{\Gamma \proves it\makes \Gamma'}
\begin{mathparpagebreakable}
  \infer[ok-type]
    {\Gamma,\overline{\alpha} \proves \textstyle\sum\overline{R}\;\mathsf{type}\quad
      \Gamma,\overline{\alpha},\overline{R}\proves\tau\;\mathsf{type}}
    {\Gamma \proves \mathsf{type}\;S(\overline{\alpha}, \overline{R}):=\tau\makes \Gamma,\ \mathsf{type}\;S(\overline{\alpha}, \overline{R}):=\tau}\and
  \infer[ok-const]
    {\Gamma\proves pe:\tau\quad
     \Gamma\proves t:\tau\Rightarrow \bar R}
    {\Gamma \proves \mathsf{const}\;t:=pe\makes \Gamma,\bar R}\and
  \infer[ok-global]
    {\Gamma\proves e:\tau\makes \Gamma'\quad
     \Gamma'\proves t:\tau\Rightarrow \bar R}
    {\Gamma \proves \mathsf{global}\;t:=e\makes \Gamma',\bar R}\and
  \infer[ok-func, ok-proc]
    {\mathbf{kw}\in\{\mathsf{func},\mathsf{proc}\}\quad \Gamma\proves \textstyle\sum\overline{R}\;\mathsf{type}\quad
      \Gamma,\overline{R} \proves\textstyle\sum\overline{S}\;\mathsf{type}\quad
      \Gamma,(\mathsf{self}(\overline{R}):\overline{S}),\overline{R} \proves e:\mathbf{0}\makesto \core{\bar R}}
    {\Gamma \proves \mathbf{kw}\;f(\overline{R}):\overline{S}:=e\makes \Gamma',\ \mathbf{kw}\;f(\overline{R}):\overline{S}}\and
\end{mathparpagebreakable}

\subsection{Uninitialized data}

The approach for handling mutation also cleanly supports uninitialized data. We extend the language as follows:

\begin{mathparpagebreakable}
  \mathrm{Type}::=\dots\mid \tau^?\and
  \mathrm{Expr}::=\dots\mid \mathsf{uninit}\and
  \core{\tau^?}=\core\tau^?\and
  \boxed{x:\tau^?}=\top\\
  \infer[ty-maybe]
    {\Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves \tau^?\;\mathsf{type}}\and
  \infer[tye-uninit]
    {\Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves \mathsf{uninit}:\tau^?}\and
\end{mathparpagebreakable}
We also modify the \textsc{cs-mut} rule:
$$\infer[cs-mut]
    {\Gamma \proves \langle \overline{x}\rangle:\textstyle\sum\core{\overline{R^?}}\quad
      \Gamma \proves \langle \overline{e}\rangle:\textstyle\sum\overline{R}}
    {\Gamma,\overline{x\gets e} \constep\Gamma_{\overline{R}}}$$
such that the variables $x$ are allowed to be potentially uninitialized versions of the types in $e$, meaning that a variable $x:\tau^?$ can change to $x:\tau$ as the result of a mutation.

\subsection{Pointers}\label{sec:pointers}

Thus far the rules have only talked about local variables and mutation of local variables, that we think of as being on the stack frame of the function. To understand the representation of pointers in the type system, it will help to understand the way contexts are modeled as separating propositions. The context is a large separating conjunction of $\boxed{x:\tau}$ assertions for every $(x^\gamma:\tau)\in\Gamma$ and $A$ for every $h:A$, plus additional ``layout'' information about the relation of non-ghost variables to the stack frame that will be calculated in the layout pass (see section \ref{sec:layout}).

\subsubsection{Singleton pointers}

The simplest pointer type is $\&^\mathbf{sn}(\eta:\tau)$. $x:\&^\mathbf{sn}(\eta:\tau)$ simply means that $x$ is a pointer that points to $\eta$, which is a ``place'', a writable location. $\core{\&^\mathbf{sn}\eta}=\N_{64}$ and $\boxed{x:\&^\mathbf{sn}\eta}=x\mapsto \eta$. Supporting these requires no significant extensions to the language. We add the following:

\begin{mathparpagebreakable}
  \mathrm{Type}::=\dots\mid \&^\mathbf{sn}(\eta:\tau)\and
  \mathrm{Expr}::=\dots\mid {}^\ast e\mid \& e\\
  \core{\&^\mathbf{sn}(\eta:\tau)}=\N_{64}\and
  \boxed{x:\&^\mathbf{sn}(\eta:\tau)}=x\mapsto \eta\\
  \infer[ty-snp]
    {\Gamma \proves \tau\;\mathsf{type}\quad
      \Gamma \proves \eta:\core\tau}
    {\Gamma \proves \&^\mathbf{sn}(\eta:\tau)\;\mathsf{type}}\and
  \infer[tye-deref]
    {\Gamma \proves e:\&^\mathbf{sn}(\eta:\tau)\makes\Gamma'\quad
      \Gamma' \proves \eta:\tau\makes\Gamma''}
    {\Gamma \proves {}^* e:\tau\makes\Gamma''}\and
  \infer[tye-ref]
    {\Gamma \proves \eta:\core\tau}
    {\Gamma \proves \&\eta:\&^\mathbf{sn}(\eta:\tau)}\and
\end{mathparpagebreakable}
To allow for mutation, we must also extend the $x\gets pe;\ e$ form to allow a pointer on the left:

\begin{mathparpagebreakable}
  \mathrm{Place}::=\dots\mid {}^\ast e\and
  \infer[tye-mut-deref]
    {\Gamma \proves e_1:\&^\mathbf{sn}(\eta:\tau)\makes\Gamma'\quad
      \Gamma' \proves (\eta\gets pe;\ e_2):\tau'\makes\Gamma''}
    {\Gamma \proves ({}^\ast e_1\gets pe;\ e_2):\tau'\makes\Gamma''}\and
\end{mathparpagebreakable}

\subsubsection{Owned pointers}

An owned pointer is also fairly simple. We define $\boxed{x:\&^\mathbf{own}\tau}$ as $\exists v:\tau,\ x\mapsto v$, but we can't directly dereference an owned pointer as we must first have access to the variable $v$, so we require that it first be destructured to be used.

\begin{mathparpagebreakable}
  \mathrm{Type}::=\dots\mid \&^\mathbf{own}\tau\and
  \core{\&^\mathbf{own}\tau}=\N_{64}\and
  \boxed{x:\&^\mathbf{own}\tau}=\exists v:\tau,x\mapsto v\\
  \infer[ty-own]
    {\Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves \&^\mathbf{own}\tau\;\mathsf{type}}\and
  \infer[tpt-own]
    {\Gamma \proves t:\textstyle \tau\Rightarrow \bar{S}\quad
      \Gamma,\bar{S} \proves t':\textstyle \&^\mathbf{sn}t\Rightarrow \bar{S}'}
    {\Gamma \proves \langle t,t'\rangle:\&^\mathbf{own}\tau\Rightarrow \bar{S},\bar{S}'}\and
\end{mathparpagebreakable}

\subsubsection{Mutable pointers}
The type $\&^\mathbf{mut}\tau$ is not a true type, but is allowed in function signatures to indicate a $\&^\mathbf{sn}(\eta:\tau)$ value where $\eta$ is external to the function. To support this we have to rewrite the provided function signature to include these $\eta$ ghost values and then match them with provided expressions.

\begin{align*}
  \rho\in\mathrm{FArg}::={}&R\mid x:\&^\mathbf{mut}\tau\\
  \mathrm{Item}::={}&\dots\mid\mathsf{func}\;f(\overline{\rho}):\overline{R}:=e\mid\mathsf{proc}\;f(\overline{\rho}):\overline{R}:=e
\end{align*}
We have to modify \textsf{ok-proc} to accomodate the new arguments:
\begin{mathparpagebreakable}
  \infer[ok-func, ok-proc]
    {\mathbf{kw}\in\{\mathsf{func},\mathsf{proc}\}\quad \Gamma\proves \overline{\rho}\;\mathsf{args}\Rightarrow\overline R\quad
      \Gamma,\overline{R} \proves\textstyle\sum\overline{S}\;\mathsf{type}\quad
      \Gamma,(\mathsf{self}(\overline{\rho}):\overline{S}),\overline{R} \proves e:\textstyle\sum\overline{S}\makesto \core{\bar \rho}}
    {\Gamma \proves \mathbf{kw}\;f(\overline{\rho}):\overline{S}:=e\makes \Gamma',\ \mathbf{kw}\;f(\overline{\rho}):\overline{S}}\and
\end{mathparpagebreakable}
where we have a new judgment for elaborating function arguments, whose only interesting case elaborates $x:\&^\mathbf{mut}\tau$ to $\ghost v:\tau,x:\&^\mathbf{sn}v$:

\judgment[Argument elaboration]{\Gamma\proves \overline{\rho}\;\mathsf{args}\Rightarrow\overline R}
\begin{mathparpagebreakable}
  \axiom[args-zero]{\Gamma\proves \cdot\Rightarrow\cdot}\and
  \infer[args-arg]
    {\Gamma\proves \overline{\rho}\Rightarrow \bar R}
    {\Gamma\proves \overline{\rho},R'\Rightarrow R,R'}\and
  \infer[args-mut]
    {\Gamma\proves \overline{\rho}\Rightarrow \bar R\quad
      \Gamma,\bar R\proves \tau\;\mathsf{type}}
    {\Gamma\proves \overline{\rho},x:\&^\mathbf{mut}\tau\Rightarrow \bar R,\ghost v:\tau,x:\&^\mathbf{sn}v}\and
\end{mathparpagebreakable}

The $\core{\bar \rho}$ that appears in \textsc{ok-proc} denotes a final function context that moves all regular function arguments, but the $\ghost v:\tau$ variables generated by $x:\&^\mathbf{mut}\tau$ elaboration are not moved. This ensures that they are still valid at function return.

Finally, we have to describe how a function is called. In short, $e$ matches an argument of type $x:\&^\mathbf{mut}\tau$ if $e:\&^\mathbf{sn}\eta$ for some $\eta$, which is ``captured'' by the function and modified, generating a fresh $v':\tau$ and a mutation record $\eta\gets v'$.

\subsubsection{Shared pointers}

Shared pointers are the most complex, because they cannot be modeled by separating conjunctions, at least without techniques such as fractional ownership. This is not a problem until we get to the underlying separation logic. Here we only need to mark work that will be perfomed later on.

We introduce a new kind of variable modifier, a heap variable. $\hat x:\tau$ means that $x:\tau$, but $x$ is not owned by the current context. Heap variables can overlap each other, but not other regular variables in the context.

Heap variables resemble shared references from Rust, and in particular they are annotated with a ``lifetime''. The difference is that the pointer-ness is separated out; a heap variable directly has the type of the pointee, and the pointer is just a $\&^\mathbf{sn}\eta$ where $\eta$ is a heap variable.

\begin{mathparpagebreakable}
  a\in\mathrm{Lft}::=\mathsf{extern}\mid x\and
  \mathrm{Arg}::=\dots\mid \mathsf{ref}^a\;x:\tau\and
  \mathrm{FArg}::=\dots\mid \mathsf{ref}\;x\and
  \mathrm{TuplePattern}::=\dots\mid \mathsf{ref}^a\;x\and
  \axiom[tpt-ref]{\Gamma \proves \mathsf{ref}^a\;x:\tau\Rightarrow \mathsf{ref}^a\;x:\tau}\and
  \infer[arg-ref]
    {\mathrm{Var}(a)\subseteq \Gamma\quad
      \Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves \mathsf{ref}^a\; x:\tau\;\mathsf{arg}}\and
  \infer[args-ref]
    {\Gamma\proves \overline{\rho}\Rightarrow \bar R\quad
      \Gamma,\bar R\proves \tau\;\mathsf{type}}
    {\Gamma\proves \overline{\rho},\mathsf{ref}\;x:\tau\Rightarrow \bar R,\mathsf{ref}^\mathsf{extern}\;x:\tau}\and
  \infer[tye-struct-ref]
    {\Gamma \proves \eta:\core\tau\quad
      \Gamma \proves \langle \overline{e}\rangle:\textstyle\sum \bar R[\eta/x]\makes\Gamma'}
    {\Gamma \proves \langle \eta,\overline{e}\rangle: \textstyle\sum \mathsf{ref}^{\mathrm{Lft}(\eta)}\;x:\tau,\bar R\makes\Gamma'}\and
  {\mathrm{Lft}(x)=x\atop
    \mathrm{Lft}(\eta[pe])=\mathrm{Lft}(\eta)}
\end{mathparpagebreakable}

Using heap variables, we can desugar shared references similarly to owned pointers:

\begin{mathparpagebreakable}
  \mathrm{Type}::=\dots\mid \&^a\tau\and
  \core{\&^a\tau}=\N_{64}\and
  \boxed{x:\&^a\tau}=\exists v:\mathsf{ref}^a\;\tau,x\mapsto v\\
  \infer[ty-shr]
    {\mathrm{Var}(a)\subseteq \Gamma\quad
      \Gamma \proves \tau\;\mathsf{type}}
    {\Gamma \proves \&^a\tau\;\mathsf{type}}\and
  \infer[tpt-shr]
    {\Gamma \proves \mathsf{ref}^a\; t:\textstyle \tau\Rightarrow \bar{S}\quad
      \Gamma,\bar{S} \proves t':\textstyle \&^\mathbf{sn}t\Rightarrow \bar{S}'}
    {\Gamma \proves \langle t,t'\rangle:\&^a\tau\Rightarrow \bar{S},\bar{S}'}\and
\end{mathparpagebreakable}

\subsection{Arrays}\label{sec:arrays}

Arrays here are fixed length, depending on another variable in the context.

\begin{mathparpagebreakable}
  \mathrm{Type}::=\dots\mid \mathsf{array}\;\tau\;pe\and
  \core{\mathsf{array}\;\tau\;n}=\mathsf{array}\;\core\tau\;n\and
  \boxed{x:\mathsf{array}\;\tau\;n}=(x:n\to\core\tau)\ast\textstyle\Sep_{i<n}\boxed{x[i]:\tau}\\
  \infer[ty-array]
    {\Gamma \proves \tau\;\mathsf{type}\quad
      \Gamma \proves n:\N_s}
    {\Gamma \proves \mathsf{array}\;\tau\;n\;\mathsf{type}}\and
\end{mathparpagebreakable}

TODO

\section{The Layout pass}\label{sec:layout}

The layout pass is responsible for assigning concrete memory locations to variables in the code. In particular, multiple variables may overlap the same memory location if they are never \emph{live} at the same time, which is to say, the last use of one variable comes before the definition of the second. The analysis pass that determines these relations is considered part of the ``nondeterministic'' part of the compiler, meaning that it requires no proof. Instead, the analysis pass produces a satisfying layout, and the typing relation will validate that a layout puts variables in disjoint locations if they are live at the same time.

To that end, we introduce another syntactic category not present in the source language, a \emph{machine place}, or M-place for short.

$$\mu::=\mathsf{Reg}\;r\mid \mathsf{Stack}\;s$$

The registers $r$ correspond to the registers on the machine, so there is one for every general-purpose register. (On x86-64 there are 16 general purpose registers, but RSP is the stack pointer, and one register is reserved by the compiler for spilling, so there are 14 registers available for use.)

The stack locations $s$ correspond to an abstraction of the stack frame, optimized for disjointness proofs. A stack frame has a series-parallel layout:
$$\phi ::= \phi_0\ast\phi_1\mid \phi_0\cup \phi_1\mid |\tau|$$
and $s$ is a path into the stack frame:
$$s ::= \mathsf{id}\mid s.0\mid s.1 \mid s.l \mid s.r$$
with the following typing rules:

\judgment[Stack variable typing]{\phi\proves s:\phi'}
\begin{mathparpagebreakable}
  \axiom[stk-id]{\phi\proves \mathsf{id}:\phi}\and
  \infer[stk-fst]
    {\phi\proves s:\phi_1\ast \phi_2}
    {\phi\proves s.0:\phi_1}\and
  \infer[stk-snd]
    {\phi\proves s:\phi_1\ast \phi_2}
    {\phi\proves s.1:\phi_2}\and
  \infer[stk-left]
    {\phi\proves s:\phi_1\cup \phi_2}
    {\phi\proves s.l:\phi_1}\and
  \infer[stk-right]
    {\phi\proves s:\phi_1\cup \phi_2}
    {\phi\proves s.r:\phi_2}
\end{mathparpagebreakable}

Intuitively, $\phi_1\ast\phi_2$ is the stack layout consisting of the layout $\phi_1$ followed by $\phi_2$ in the bytes immediately after, while $\phi_1\cup\phi_2$ consists of $\phi_1$ and $\phi_2$ superimposed on the same bytes (taking up size equal to the larger of the two).

At a given point in execution, each of the unions has one of its members ``active'' and the other ``inactive'', and a variable can only be accessed if it is active in all parent unions.
A ghost variable is never assigned any stack location and hence it can never be accessed. More formally, we say that two stack paths are \emph{incompatible}, written $s_1\perp s_2$, if there exists $s$ such that $s_1$ extends $s.l$ and $s_2$ extends $s.r$, or vice versa. We will maintain the invariant that if two variables in the context are represented by stack paths $s_1$ and $s_2$ then they are compatible.

\end{document}