\documentclass[10pt]{sigplanconf}

\usepackage[compact]{titlesec}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{url}
\usepackage{color}
\usepackage{multirow}

\setlength{\textfloatsep}{8pt}

\newcommand{\Value}{\mathbf{value}}
\newcommand{\Any}{\mathbf{any}}
\newcommand{\Nil}{\mathbf{nil}}
\newcommand{\Self}{\mathbf{self}}
\newcommand{\False}{\mathbf{false}}
\newcommand{\True}{\mathbf{true}}
\newcommand{\Boolean}{\mathbf{boolean}}
\newcommand{\Integer}{\mathbf{integer}}
\newcommand{\Number}{\mathbf{number}}
\newcommand{\String}{\mathbf{string}}
\newcommand{\Void}{\Nil{*}}
\newcommand{\Const}{\mathbf{const}}

\newcommand{\mylabel}[1]{\; (\textsc{#1})}
\newcommand{\env}{\Gamma}
\newcommand{\penv}{\Pi}
\newcommand{\senv}{\Sigma}
\newcommand{\subtype}{<:}
\newcommand{\ret}{\rho}
\newcommand{\self}{\sigma}

\def\dstart{\hbox to \hsize{\vrule depth 4pt\hrulefill\vrule depth 4pt}}
\def\dend{\hbox to \hsize{\vrule height 4pt\hrulefill\vrule height 4pt}}

\begin{document}

\toappear{}

\special{papersize=8.5in,11in}
\setlength{\pdfpageheight}{\paperheight}
\setlength{\pdfpagewidth}{\paperwidth}

\conferenceinfo{DLS '15}{October 27th, 2015, Pittsburgh, PA, USA}
\copyrightyear{2015}
\copyrightdata{978-1-nnnn-nnnn-n/yy/mm}
\doi{nnnnnnn.nnnnnnn}

\titlebanner{Draft}
\preprintfooter{A Formalization of Typed Lua}

\title{A Formalization of Typed Lua}

\authorinfo{André Murbach Maidl}
           {PUC-Rio, Brazil}
           {amaidl@inf.puc-rio.br}
\authorinfo{Fabio Mascarenhas}
           {UFRJ, Brazil}
           {mascarenhas@acm.org}
\authorinfo{Roberto Ierusalimschy}
           {PUC-Rio, Brazil}
           {roberto@inf.puc-rio.br}

\maketitle

\begin{abstract}
Programmers often migrate from a dynamically typed
to a statically typed language when their simple scripts
evolve into complex programs. Optional type systems are
one way of having both static and dynamic typing
in the same language, while keeping its dynamically typed
semantics. This makes evolving a program from dynamic to
static typing a matter of describing the implied types that
it is using and adding annotations to make those types explicit.
Designing an optional type system for
an existing dynamically typed language is challenging, as its types should feel natural to programmers that are already familiar with
this language.

In this work, we give a formal description of Typed Lua, an
optional type system for Lua, with a focus on two of its novel type system features: incremental evolution of imperative record and object types that is both lightweight and type-safe, and {\em projection types}, a combination of flow typing, functions that return multiple values, and multiple assignment. While our type system is tailored to the features and idioms of Lua, its features can be adapted to other imperative scripting languages.
\end{abstract}

\category{D.3.1}{Programming Languages}{Formal Definitions and Theory}[Type Systems]

\terms
Languages, Design

\keywords
Optional Type Systems, Gradual Typing, Lua

\section{Introduction}
\label{sec:intro}

Dynamically typed languages forgo static type checking
in favor of using run-time {\em type tags} to classify
the values they compute, so its operations can use these
tags to perform run-time (or dynamic) checks and signal
errors in case of invalid operands~\cite{pierce2002tpl}.
The lack of static types allows programmers to write code
that might have required a complex type system to statically
type, at the cost of hiding defects that will only be caught
after deployment if the programmers do not properly
test their code.

In contrast, statically typed languages help programmers
detect defects during development, and also provide
a conceptual framework that helps programmers define modules
and interfaces that can be combined to structure the development
of large programs.

The early error detection and better tools for structuring
programs are two advantages of statically typed languages that
lead programmers to migrate their code from a dynamically
typed to a statically typed language when their scripts
evolve into complex programs~\cite{tobin-hochstadt2006ims}.
This migration from dynamic to static typing usually involves
different languages that have distinct syntax and semantics,
requiring a complex rewrite of existing programs instead of
incremental evolution.

Ideally, programming languages should offer programmers the
option to choose between static and dynamic typing.
\emph{Optional type systems}~\cite{bracha2004pluggable} and
\emph{gradual typing}~\cite{siek2006gradual} are two
approaches for blending static and dynamic typing in the same
language. Their aim is to offer programmers the option
of adding type annotations where static typing is needed,
allowing the incremental migration from dynamic to static
typing.

The difference between these two approaches is the
way they treat the runtime semantics of the language:
optional type systems have the {\em trace preservation}
property~\cite{strongscript}, where type annotations
do not influence runtime behavior, and the original
semantics of the dynamically typed language is preserved,
 while gradual typing changes the semantics to
include more extensive runtime checking in the
interface between typed and untyped code.
In an optionally-typed language, dynamically typed code
can lead to type errors in statically typed code, even
if the optional type system is sound. In a gradually-typed
language, the extra runtime checks ensure that
this does not occur.
 The decision
between the two approaches is not binary, and languages
can have both optional and gradual types~\cite{liketypes,strongscript}.

A key feature in optional type systems is usability.
Optional type systems retrofitted to an existing
language should fit the language's idioms, adding
static type safety to them. If the system is too
simple it may require too much of a change in the way
programmers use the language. On the other hand,
if it is too complex it may overload the programmers
with types and error messages that are hard to
understand. The most challenging aspect of designing optional type systems is to find the right amount of complexity for a type system that feels natural to the programmers.

Lua is a small imperative language with lexically-scoped first-class functions where the only data structuring
mechanism is the \emph{table}, an associative array. Lua prefers to provide mechanisms instead of fixed policies due
to its primary use as an embedded language for configuration and
extension of other applications.
This means that even features such as a module system and
object orientation are a matter of convention on how
programs use the syntactic sugar and metaprogramming
facilities of tables, instead of
built-in language constructs. Tables can efficiently represent arrays, records, maps, modules,
objects, etc.

The result is a fragmented ecosystem of libraries, and different
ideas among Lua programmers on how they should use the language
features or on how they should structure programs. One example
of this fragmentation is the proliferation of object systems.

Typed Lua~\cite{maidl2014tl,maidl2015tl} is an optional type system for
Lua that is rich enough to preserve some of the idioms
that Lua programmers are already familiar with, while
helping programmers structure large Lua programs and
catch errors at compile-time.

In this paper, we give a formal basis to an updated version of Typed Lua's original design, with a focus on two novel type system
features that Typed Lua uses to type some tricky Lua idioms.
The lack of standard policies is a challenge for the design of
an optional type system for Lua. For this reason, the design
of Typed Lua has been informed by a mostly automated survey
of Lua idioms used by a large corpus of Lua libraries.
This paper also presents the methodology of this survey and
a summary of its results.

The first idioms that we focus on this paper is the use of assignment to build records and objects one field at a time, as in
the Lua fragment in Figure~\ref{fig:newpoint}, where the {\tt new\_point} function
is a constructor for objects with {\tt x} and {\tt y}
fields and a {\tt move} method.

\begin{figure}[t]
{\footnotesize
\begin{verbatim}
  function new_point(x, y)
    local point = {}
    point.x, point.y = x, y
    function point:move(dx, dy)
      self.x, self.y = self.x + dx, self.y + dy
    end
    return point
  end
\end{verbatim}
}
\caption{Building an object piece-by-piece}
\label{fig:newpoint}
\end{figure}

The {\tt new\_point} function builds the object piece-by-piece,
from an initially empty table. Typed Lua
lets record and object types evolve incrementally
via assignment while not sacrificing width subtyping,
where we can form a supertype of a table type by ``forgetting'' fields.

The other idiom that we focus on combines overloading on the return values of a function, multiple return values, multiple assignment
to decompose multiple return values,
and tag checks to discriminate several returned values
by checking just one of them. The Lua fragment in Figure~\ref{fig:over} shows a function with overloaded multiple
returns, and how a caller of this function can discriminate
which list of multiple values the function returned.

\begin{figure}[t]
{\footnotesize
\begin{verbatim}
  function idiv(x, y)
    if y == 0 then return nil, "division by zero"
    else return x // y, x % y end
  end

  local q, r = idiv(a, b)
  if q then assert(a == q*b + r)
  else error(r) end
\end{verbatim}
}
\caption{Overloading on multiple returns}
\label{fig:over}
\end{figure}

In the {\bf then} branch it is guaranteed that both {\tt q}
and {\tt r} are integers, and in the {\bf else} branch it is
guaranteed that {\tt q} is {\tt nil} and {\tt r} is a string.
In Typed Lua, the return type of {\tt idiv} can be a union of
tuples describing the possible return values. Typed Lua deconstructs unions of tuples into {\em projection types}, and these types track
the dependencies between the types of each value in the tuple.

The remainder of the paper is organized as follows:
Section \ref{sec:statistics} presents the methodology and results of
our survey of Lua idioms;
Section \ref{sec:types} presents the types of Typed Lua's
type system; Section~\ref{sec:subtyping} presents
their subtyping and consistent-subtyping relations;
Section \ref{sec:rules} presents the typing rules
for the two idioms that we focus on this paper;
Section \ref{sec:related} reviews related work;
Section \ref{sec:conclusion} presents our conclusions,
and outlines plans for future work.

\section{A Survey of Lua Idioms}
\label{sec:statistics}

In order to find out how Lua is used in practice, to inform
the design of Typed Lua, we did a survey of existing Lua
libraries. Our corpus is the repository for the LuaRocks
package manager~\cite{hisham2013luarocks}, downloaded on
February 1st, 2014. We did not survey all of the Lua
scripts in the repository: scripts that were not compatible
with Lua 5.2 (the version of Lua at that time) were ignored,
and we also ignored machine-generated scripts and test scripts,
as those could skew the result towards non-idiomatic uses
of Lua. This left 2,598 scripts out of a total of 3,928, from
262 different projects. The scripts were parsed, and their
abstract syntax trees analyzed to collect the data that we
show in the rest of this section.

Tables are the core data structure of Lua programs, and
the language has features that let tables be used as
tuples, lists, maps, records, abstract data types, classes,
objects, modules, etc. We performed several analyses to
quantify the different ways that Lua programs use tables.

Our first analysis surveyed table constructors (expressions
that create and initialize a table) to find out how a table
begins its life. Of all of the 23,185 table constructors of
our corpus, 36\% of them create a record (a table with string
keys such as \texttt{\{x = 1, y = 2\}}), 29\% of them create
a list or a tuple (a table with consecutive integer keys such as \texttt{\{"one", "two", "three", "four"\}}), 26\% of them create an empty table, and 8\% of them create a table with
both a record part and a list part. The remaining 1\% of them create a table with non-literal keys.

We also analyzed expressions that access a table (130,448 instances), either to read a value out of it (86\% of such expressions) or to write a
value into it (14\% of such expressions). Most of the expressions
that read a value out of a table use a literal key,
either a literal string (89\% of the reads) or a literal
number (4\% of the reads). Lua has syntactic sugar that
turns field accesses using ``dot'' notation into table
accesses through literal string keys.

In 45\% of the expressions that read a value out of a table,
its value is immediately called. These calls are split almost
evenly between function calls and method calls (25\% of reads
are function calls, 20\% of reads are method calls).
These results show that the use of tables as a namespacing
mechanism for modules, as objects, and as records,
is prevalent.

Expressions that write into a table also mostly use
literal keys (69\% of them use a literal string, 2\%
of them use a literal number), although a large 29\%
of writes use non-literal keys, in contrast to only 7\% of
reads.

In order to gauge how frequently tables are used as
collections, we looked for the presence of code that
iterates over tables, and found out that 23\% of the
scripts in our corpus iterate over a map at least once,
and 27\% of the scripts iterate over a list at least once.

Besides measuring the number of method calls, we also
measured other kinds of expressions and statements to gauge
how frequently Lua programmers use the object-oriented paradigm.
Our corpus has 24,858 function declarations, and 23\% of these
are method declarations. Of the 262 projects in our corpus,
63\% use {\em metatables}, a metaprogramming mechanism that
lets the program extend the behavior of tables and is mostly
used for implementing prototype-based inheritance.

Typed Lua's table types, described in the next section,
reflect the way Lua programmers use Lua tables in practice,
according to the results above. A table type can express
records, tuples, maps, lists, objects, or a combination of
those.

Lua modules are tables containing the modules' exports.
The current idiomatic way to define a module is to populate
an initially empty table with the members the module wishes
to export, and return this table at the end of the script
that defines the module. Around two-thirds of the modules
in our corpus use this idiom. The other third uses a
deprecated idiom, where a call to the {\tt module} function
at the top of the script installs a new global environment,
and the exported members are global variables assigned to
in the rest of the module.

The global environment is a also a table, so the two idioms
are equivalent in terms of how Typed Lua deals with module
definitions. Modules in Typed Lua make extensive use of Typed
Lua's rules for evolution of table types
(Section~\ref{sec:tables}).

In order to gauge how common is the use of dynamic type
checking as a way to define overloaded functions, we
measured how many of the functions inspect the
tags of their input parameters, and found out that 9\%
of the functions in our corpus do this, split evenly
between using the tag in an assertion, as a form of
type checking, and using the tag to decide which code
to execute, as a form of overloading. While Typed Lua
supports both union types and flow typing, general
support for overloaded functions still has to improve.

A Lua idiom that is specially problematic for static type
systems is overloading on the number and types and
multiple return values. Around 6\% of functions use
this idiom as a way to signal errors: in case of errors,
the function returns either {\tt nil} or {\tt false} plus
either an error message or error object instead of its usual
return values or throwing an exception. The caller then
tests the first returned value to check if an error occurred
or not. Standard union types and flow typing cannot deal
with this, and Typed Lua introduces {\em projection types},
a way of tracking dependencies between types in a union of
tuples after a destructuring assignment.

\section{Types}
\label{sec:types}

\begin{figure}[t]
{\scriptsize
$$
\begin{array}{rlr}
F ::= & & \textsc{first-level types:}\\
& \;\; L & \textit{literal types}\\
& | \; B & \textit{base types}\\
& | \; \Nil & \textit{nil type}\\
& | \; \Value & \textit{top type}\\
& | \; \Any & \textit{dynamic type}\\
& | \; \Self & \textit{self type}\\
& | \; F_{1} \cup F_{2} & \textit{union types}\\
& | \; S_{1} \rightarrow S_{2} & \textit{function types}\\
& | \; \{\overline{F:V}\}_{unique|open|fixed|closed} & \textit{table types}\\
& |\; x & \textit{type variables}\\
& | \; \mu x.F & \textit{recursive types}\\
%\multicolumn{3}{c}{}\\
L ::= & & \textsc{{\tiny literal types:}}\\
&  \False \; | \; \True \; | \; {\it int} \; | \; {\it float} \; | \; {\it string} &\\
%\multicolumn{3}{c}{}\\
B ::= & & \textsc{{\tiny base types:}}\\
& \Boolean \, |\,  \Integer \, |\, \Number\, |\, \String &\\\\
%\multicolumn{3}{c}{}\\
%\multicolumn{3}{c}{}\\
V ::= & & \textsc{{\tiny value types:}}\\
& \;\; F \; | \; \Const \; F &\\
S ::= & & \textsc{second-level types:}\\
& \;\; P & \textit{tuple types}\\
& | \; S_{1} \sqcup S_{2} & \textit{unions of tuple types}\\
%\multicolumn{3}{c}{}\\
P ::= & & \textsc{{\tiny tuple types:}}\\
%& \;\; \Void & \textit{void type}\\
& | \; F{*} & \textit{variadic types}\\
& | \; F \times P & \textit{pair types}\\\\
\end{array}
$$
}
\caption{Type Language}
\label{fig:typelang}
\end{figure}

\begin{figure}[t]
{\footnotesize
$$
\begin{array}{rlr}
T ::= & & \textsc{expression types:}\\
& \;\; F & \textit{first-level types}\\
& | \; \phi(F_{1},F_{2}) & \textit{filter types}\\
& | \; \pi_{i}^{x} & \textit{projection types}\\
E ::= & & \textsc{expression list types:}\\
& \;\; T{*} & \textit{variadic types}\\
& | \; T \times E & \textit{pair types}\\
%K ::= & & \textsc{{\small key types:}}\\
%& \;\; L \; | \; B \; | \; \Value &\\
%\multicolumn{3}{c}{}\\
R ::= & & \textsc{filter result type:}\\
& \;\; \mathbf{void} & \textit{void type}\\
& |\; F & \textit{first-level types}
\end{array}
$$
}
\caption{Special Types}
\label{fig:special}
\end{figure}

Figure~\ref{fig:typelang} presents the abstract syntax of
the core Typed Lua types. They are split into two categories:
\emph{first-level types} and \emph{second-level types}.
First-level types represent first-class Lua values and
second-level types represent tuples of values that appear
as parameters and return values of functions.

Types are ordered by a subtype relationship, so Lua values may belong to several distinct types. The details of the subtyping
relationship are given later in Section~\ref{sec:subtyping}.

Literal types represent the type of literal boolean, number
and string values. Having just one value each, their main application is in constructing table types with fields where it is guaranteed that the value of that field will not be {\tt nil}.

The base types represent values that Lua tags as booleans,
strings, or numbers during runtime. Prior to version Lua 5.3 all Lua numbers were double-precision floating point numbers.
Lua 5.3 introduced the possibility of having 64-bit integers
as numbers, with automatic promotion of integer values to
floating-point representation as needed. As automatic
promotion makes integers essentially subtypes of floating-point numbers, Typed Lua uses $\Number$ as the type of floating-point numbers, and $\Integer$ as the type of integers.

The type $\Nil$ is the type of {\tt nil}, the value that Lua uses for undefined variables, missing parameters, and missing table keys.
Many programming languages include a bottom type to represent
an empty value that programmers can use as a default expression.
We could have used the type $\Nil$ for this role, but
this would lead to reduced static type safety. Typed Lua's
type system does not have a bottom type.

The type $\Value$ is the top type, which represents any Lua value.
Its main purpose is to be able to easily express function types
that silently ignore extra arguments, as well as easily ignoring extra r-values in multiple assignment, preserving the semantics of Lua for these operations, as they do not sacrifice type safety.

The type $\Self$ is the receiver in object-oriented method
definitions and method calls, and lets Typed Lua have objects
as regular table types with methods as regular function types
with an explicit receiver parameter.

Table types represent some of the forms that Lua
tables can take. What a particular table type denotes
depends on its {\em tag}: the {\em unique}, {\em open}
and {\em fixed} tags all denote tables where it is
guaranteed that every key belongs to one of the {\em key
types} $F_i$.

%We restrict key types to literal types,
%base types, and the top type to make the system simpler
%for the user, as our survey of Lua programs showed that
%this restriction reflects the way Lua tables are commonly used.

Fields are assignable by default, but can be marked
as non-assignable with the {\bf const} qualifier in its key type.
Having a field be {\bf const} is not a guarantee that its
value cannot change, as the table may have aliases with
a non-{\bf const} type for that field. Non-assignable
fields enable {\em depth subtyping} between table types: these
fields are covariant on the types of their values, while
assignable fields are always invariant.

The difference between {\em unique}, {\em open} and
{\em fixed} tables is the guarantees that the type system
gives about the reference to a value of that type. A
reference to an {\em unique} table is guaranteed to
point to a table that has no other references to it,
so it allows greater flexibility in reinterpreting its type;
a reference to an {\em open} table is guaranteed to have
only {\em closed} references pointing to the
same table (we will explain the meaning of the {\em closed} tag shortly), which still lets the type system
reinterpret the type of a reference, but with more
restrictions; a reference to a {\em fixed} table can have any number of
{\em fixed} or {\em closed} references point to it,
so its type cannot change
anymore.

Table types with the {\em fixed} tag are suitable for typing tables that are used as maps, lists, or even a mixture of those. The guarantee that there are no keys with a type that is not
one of the key types allows type-safe iteration on these
tables.

This guarantee forbids width subtyping, which is a necessity
for object-oriented programming, so we have the {\em closed}
tag, which removes the guarantee and allows width subtyping
between other table types and {\em closed} table types. A {\em closed} table type is akin to an object-oriented {\em interface}.

Any table type has to be \emph{well-formed}.
Informally, a table type is well-formed if key types do not overlap. A formal definition of this relation depends on
the consistent-subtyping relation which we present in the
next section, so we delay the definition until Section~\ref{sec:tables}, where the typing rules for
table types are explained.

The type $\Any$ is the dynamic type, and allows
interaction between statically and dynamically typed
portions of a program. It is neither a top nor a bottom
type, although it can work as either, as a value of
any type can be coerced to $\Any$ and vice-versa.
Gradual type systems augment these coercions with
information that can be used to blame the dynamically
typed part of the program for type errors that may occur in the
statically typed part. Currently Typed Lua only
warns the programmer that coercions to and from $\Any$
may be unsafe.

Second-level types are either tuple types or unions of tuple types, and represent sequences of values that appear as arguments, return values, and the left and right sides of
assignments. Tuple types are heterogeneous lists of first-level
types that end with a {\em variadic type}.
A variadic type $F{*}$ represents an unbounded sequence of values of type $F \cup \Nil$. Lua pads sequences with {\tt nil} to
have as many values as needed, and in Typed Lua sequences
where the number of values is statically known have a $\Nil{*}$
tail to reflect this semantics.

For clarity, we use the symbol $\sqcup$ to represent the union between two different tuple types, and reserve $\cup$ for the
union of two first-level types.

Figure~\ref{fig:special} presents some types that, while
they may not be present in type annotations, play some
special role in the type system. {\em Expression types}
denote the type of expressions in the type system, which,
in addition to first-level types, can also be
{\em filter types}, which are the result of flow typing,
and {\em projection types}, which are the result of
decomposing a union of tuples. {\em Expression list types}
denote the type of lists of expressions.
Finally, {\em filter result types}
are also used in flow typing; the {\bf void} type is
a type with no values.

\section{Subtyping and Consistent-Subtyping}
\label{sec:subtyping}

Typed Lua's type system uses subtyping to order
its types and  consistent-subtyping~\cite{siek2007objects,siek2013mutable}
to model compatibility between types in a way that allows
the interaction between statically and dynamically typed
parts of the program without collapsing the subtyping
relation.

The consistent-subtyping relation is defined in terms
of subtyping, so we focus the discussion in this section
on characterizing the subtyping relation.

The subtyping rules are a deduction system for the
subtyping relation $\subtype$ between two types of the
same kind.
The variable $\senv$ is a set of subtyping assumptions used
by the subtyping relation between recursive types.
Most of the subtyping rules are standard, so we will
focus on the interesting cases.

\begin{figure}[t]
{\footnotesize
\[
\begin{array}{c}
\begin{array}{c}
\mylabel{S-Pair}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2} \;\;\;
	\senv \vdash P_{1} \subtype P_{2}}
{\senv \vdash F_{1} \times P_{1} \subtype F_{2} \times P_{2}}
\end{array}
\begin{array}{c}
\mylabel{S-Variadic}\\
\dfrac{\senv \vdash F_{1} \cup \Nil \subtype F_{2} \cup \Nil}
{\senv \vdash F_{1}{*} \subtype F_{2}{*}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-VarExpand}\\
\dfrac{\senv \vdash F_{1} \cup \Nil \subtype F_{2} \;\;\;
	\senv \vdash F_{1}{*} \subtype P_{2}}
{\senv \vdash F_{1}{*} \subtype F_{2} \times P_{2}}
\end{array}
\\ \\
\begin{array}{c}
\mylabel{S-VarDrop}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2} \cup \Nil \;\;\;
	\senv \vdash P_{1} \subtype F_{2}{*}}
{\senv \vdash F_{1} \times P_{1} \subtype F_{2}{*}}
\end{array}
\end{array}
\]
}
\caption{Subtyping for second-level types}
\label{fig:subtuples}
\end{figure}

Figure~\ref{fig:subtuples} shows the subtyping rules for
second-level types. Expression list types have similar
subtyping rules. Tuple types are covariant, so the subtyping rule {\sc S-Pair} for pair types is straightforward.

The semantics of Lua lets the right-hand side of an assignment
produce more values than l-values in the left-hand side,
with extra values silently dropped. It also lets the
right-hand side produce fewer values than l-values in the
left-hand side, using {\tt nil} to plug the holes. The
same behavior applies for lists of arguments vs. parameters.

Typed Lua preserves this behavior in assignment by synthesizing
tuple types that have a $\Value{*}$ tail for the left side
of an assignment. Non-variadic functions have a stricter
behavior: their parameter lists have a $\Nil{*}$ tail, so
a function can be passed any number of extra arguments
as long as they are literal {\tt nil}, but the type system will
reject extra arguments of any other type. Missing arguments
are also fine if the corresponding parameters have {\tt nil}
as a subtype: this is the Lua idiom for optional parameters.

Functions that want to keep the Lua behavior of just ignoring
any extra arguments can be variadic with type $\Value{*}$ as
the tail of their parameter tuple.

The remaining subtyping rules for second-level types
reflect this semantics. Rule {\sc S-Variadic} states
that variadic types are covariant (just having $F_1{*} \subtype F_2{*}$ iff $F_1 \subtype F_2$ would be too restrictive,
as $\Nil{*}$ would not be a subtype of $\Number{*}$).
Rules {\sc S-VarExpand} and {\sc S-VarDrop} state the
conditions when variadic tuples of different length are
compatible.

We could have the axioms $\senv \vdash F{*} \subtype F \cup \Nil \times F{*}$ and $\senv \vdash F \cup \Nil \times F{*}  \subtype F{*}$ instead of the two rules above, which can be derived
from these axioms by transitivity, but having the rules makes
the subtyping relation easier to implement.

\begin{figure}[t]
{\footnotesize
\[
\begin{array}{c}
\begin{array}{c}
\mylabel{S-TableFCtoC}\\
\dfrac{\begin{array}{c}
	\forall j \; \exists i \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \;\
	\senv \vdash F_{j}' \subtype F_{i} \;
	\senv \vdash V_{i} \subtype_{c} V_{j}'
	\end{array}}
{\begin{array}{c}
	\senv \vdash \{\overline{F:V}\}_{fixed|closed} \subtype
	\{\overline{F^\prime:V^\prime}\}_{closed}
	\end{array}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-TableUtoC}\\
\dfrac{\begin{array}{c}
	\forall i \; \forall j \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \to \senv \vdash V_{i} \subtype_{u} V_{j}' \\
	\forall j  \; \nexists i \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \to \senv \vdash \Nil \subtype_{o} V_{j}'
	\end{array}}
{\senv \vdash \{\overline{F:V}\}_{unique} \subtype
	\{\overline{F^\prime:V^\prime}\}_{closed}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-TableOtoC}\\
\dfrac{\begin{array}{c}
	\forall i \; \forall j \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \to \senv \vdash V_{i} \subtype_{c} V_{j}' \\
	\forall j \; \nexists i \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \to \senv \vdash \Nil \subtype_{o} V_{j}'
	\end{array}}
{\senv \vdash \{\overline{F:V}\}_{open} \subtype
	\{\overline{F^\prime:V^\prime}\}_{closed}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-TableUtoUOF}\\
\dfrac{\begin{array}{c}
	\forall i \; \exists j \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \land \senv \vdash V_{i} \subtype_{u} V_{j}' \\
	\forall j  \; \nexists i \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \to \senv \vdash \Nil \subtype_{o} V_{j}'
	\end{array}}
{\begin{array}{c}
	\senv \vdash \{\overline{F:V}\}_{unique} \subtype
	\{\overline{F^\prime:V^\prime}\}_{unique|open|fixed}
	\end{array}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-TableOtoOF}\\
\dfrac{\begin{array}{c}
	\forall i \; \exists j \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \land \senv \vdash V_{i} \subtype_{c} V_{j}' \\
	\forall j \; \nexists i \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \to \senv \vdash \Nil \subtype_{o} V_{j}'
	\end{array}}
{\begin{array}{c}
	\senv \vdash \{\overline{F:V}\}_{open} \subtype
	\{\overline{F^\prime:V^\prime}\}_{open|fixed}
	\end{array}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-TableFtoF}\\
\dfrac{\begin{array}{c}
	\forall j \; \exists i \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \;
	\senv \vdash F_{j}' \subtype F_{i} \;
	\senv \vdash V_{i} \subtype_{c} V_{j}'\\
	\forall i \; \exists j \;\;\;
	\senv \vdash F_{i} \subtype F_{j}' \;
	\senv \vdash F_{j}' \subtype F_{i} \;
	\senv \vdash V_{i} \subtype_{c} V_{j}'\\
	\end{array}}
{\senv \vdash \{\overline{F:V}\}_{fixed} \subtype
	\{\overline{F^\prime:V^\prime}\}_{fixed}}
\end{array}
\end{array}
\]
}
\caption{Subtyping for table types}
\label{fig:tablesub}
\end{figure}

\begin{figure}[t]
{\footnotesize
\[
\begin{array}{c}
\begin{array}{c}
\mylabel{S-FieldClsMtoM}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2} \;\;\;
	\senv \vdash F_{2} \subtype F_{1}}
{\senv \vdash F_{1} \subtype_{c} F_{2}}
\end{array}
\;
\begin{array}{c}
\mylabel{S-FieldClsItoI}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2}}
{\senv \vdash \Const \; F_{1} \subtype_{c} \Const \; F_{2}}
\end{array}
\\ \\
\begin{array}{c}
\mylabel{S-FieldClsMtoI}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2}}
{\senv \vdash F_{1} \subtype_{c} \Const \; F_{2}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-FieldUnqMtoM}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2}}
{\senv \vdash F_{1} \subtype_{u} F_{2}}
\end{array}
\;
\begin{array}{c}
\mylabel{S-FieldUnqItoM}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2}}
{\senv \vdash \Const \; F_{1} \subtype_{u} F_{2}}
\end{array}
\\ \\
\begin{array}{c}
\mylabel{S-FieldUnqItoI}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2}}
{\senv \vdash \Const \; F_{1} \subtype_{u} \Const \; F_{2}}
\end{array}
\;
\begin{array}{c}
\mylabel{S-FieldUnqMtoI}\\
\dfrac{\senv \vdash F_{1} \subtype F_{2}}
{\senv \vdash F_{1} \subtype_{u} \Const \; F_{2}}
\end{array}
\\ \\
\begin{array}{c}
\mylabel{S-FieldOpnNtoM}\\
\dfrac{\senv \vdash \Nil \subtype F}
{\senv \vdash \Nil \subtype_{o} F}
\end{array}
\;
\begin{array}{c}
\mylabel{S-FieldOpnNtoI}\\
\dfrac{\senv \vdash \Nil \subtype F}
{\senv \vdash \Nil \subtype_{o} \Const \; F}
\end{array}
\end{array}
\]
}
\caption{Subtyping for fields}
\label{fig:subfield}
\end{figure}

Figure~\ref{fig:tablesub} shows the subtyping rules for
table types. These rules use the auxiliary relations
$\subtype_{c}$, $\subtype_{u}$, and $\subtype_{o}$
shown in Figure~\ref{fig:subfield} to handle depth
subtyping where applicable.

Rule {\sc S-TableFCtoC} for subtyping
between a {\em fixed} or {\em closed}
table type and a {\em closed} table type resembles the
standard subtyping rule between mutable records, with
width subtyping plus depth subtyping from a mutable
or immutable field to an immutable field.

Rule {\sc S-TableUtoC} for subtyping between {\em unique} and {\em closed} table types is more permissive, as the typing rules of Section~\ref{sec:tables} guarantee that an {\em unique}
table type can only appear on the left side of a subtyping
judgment if the reference to the table with the {\em unique}
tag is being destroyed. This rule allows width subtyping, depth subtyping on any field, not only immutable fields, as well as the addition of new fields and the merging of existing fields, as long as the types of the values of new and merged fields include $\Nil$.

The rationale for the permissiveness of {\sc S-TableUtoC} derives from the fact that reading a non-existing key just yields $\Nil$ instead of being an error in Lua semantics, plus the fact
that the type system guarantees that a table with an
{\em unique} type has no keys with a value that does not
belong to one of its key types, and does not have any
aliases. With these guarantees, a table with type $\{1{:}\String, 2{:}\String,
``x"{:}\Integer, ``y"{:}\Value\}_{unique}$ can be safely recast as a table with type
$\{\Number{:}\String \cup \Nil, ``x"{:}\Number, ``z"{:}
\Number \cup \Nil\}_{closed}$ as long as it becomes
inaccessible with the original type, which Section~\ref{sec:tables} will show that is the case
for any type judgment where this subtyping rule is used.

Rule {\sc S-TableOtoC} for subtyping from an {\em open} table type to a {\em closed} table type also allows width subtyping, merging fields, and adding new fields, but forbids depth subtyping between mutable fields or an immutable and a mutable field, as the typing rules guarantee that the {\em open} reference
is destroyed, but the {\em open} table may already have {\em closed} aliases.

Rule {\sc S-TableUtoUOF} for subtyping from {\em unique} to {\em unique}, {\em open} or {\em fixed} table types is still permissive, but forbids standard width subtyping, as all these table types keep the guarantee that the values of all keys in tables of these types belong to one of their key types. Merging fields and adding new fields are still allowed.

Rule {\sc S-TableOtoOF} for subtyping from {\em open} to {\em open} or {\em fixed} table types mixes the depth subtyping restrictions of rule {\sc S-TableOtoC} with the width subtyping restrictions of rule {\sc S-TableUtoUOF}, but still allows merging fields and adding new fields.

Finally, rule {\sc S-TableFtoF} for subtyping between {\em fixed} table types is the most restrictive, and does not allow width
subtyping, merging fields, or adding fields, just standard
depth subtyping.

We will revisit the subtyping rules among table types in
Section~\ref{sec:tables}.

\begin{figure}[t]
{\footnotesize
\[
\begin{array}{c}
\begin{array}{c}
\mylabel{S-Amber}\\
\dfrac{\senv[x_{1} \subtype x_{2}] \vdash F_{1} \subtype F_{2}}
{\senv \vdash \mu x_{1}.F_{1} \subtype \mu x_{2}.F_{2}}
\end{array}
\;
\begin{array}{c}
\mylabel{S-Assumption}\\
\dfrac{x_{1} \subtype x_{2} \in \senv}
{\senv \vdash x_{1} \subtype x_{2}}
\end{array}\\\\
\begin{array}{c}
\mylabel{S-UnfoldRight}\\
\dfrac{\senv \vdash F_{1} \subtype [x \mapsto \mu x.F_{2}]F_{2}}
{\senv \vdash F_{1} \subtype \mu x.F_{2}}
\end{array}
\;
\begin{array}{c}
\mylabel{S-UnfoldLeft}\\
\dfrac{\senv \vdash [x \mapsto \mu x.F_{1}]F_{1} \subtype F_{2}}
{\senv \vdash \mu x.F_{1} \subtype F_{2}}
\end{array}
\end{array}
\]
}
\caption{Subtyping for recursive types}
\label{fig:subrec}
\end{figure}

\begin{figure}[t]
{\scriptsize
	$$
	\begin{array}{rlr}
	s ::= & & \textsc{statements:}\\
	& \;\; \mathbf{skip} & \textit{skip}\\
	& | \; s_{1} \; ; \; s_{2} & \textit{sequence}\\
	& | \; \overline{l} = el & \textit{multiple assignment}\\
	& | \; \mathbf{while} \; e \; \mathbf{do} \; s \;
	| \; \mathbf{if} \; e \; \mathbf{then} \; s_{1} \; \mathbf{else} \; s_{2} & \textit{control flow}\\
	& | \; \mathbf{local} \; \overline{id{:}F} = el \; \mathbf{in} \; s & \textit{variable declaration}\\
	& | \; \mathbf{local} \; \overline{id} = el \; \mathbf{in} \; s & \textit{variable declaration}\\
	& | \; \mathbf{rec} \; id{:}F = e \; \mathbf{in} \; s & \textit{recursive declaration} \\
	& | \; \mathbf{return} \; el & \textit{return} \\
	& | \; \lfloor a \rfloor_{0} & \textit{function call}\\
	& | \; \mathbf{fun} \; id_{1}{:}id_{2} \; (pl){:}S \; s \;;\; \mathbf{return} \; el & \textit{method declaration}\\
	e ::= & & \textsc{expressions:}\\
	& \;\; \mathbf{nil} & \textit{nil}\\
	& | \; k & \textit{other literals}\\
	& | \; id & \textit{variable access}\\
	& | \; e_{1}[e_{2}] & \textit{table access}\\
	& | \; {<}F{>} \; id & \textit{type coercion}\\
	& | \; f & \textit{function declaration}\\
	& | \; \{ \; \overline{[e_{1}] = e_{2}} \; \} \;
	| \; \{ \; \overline{[e_{1}] = e_{2}},me \; \} & \textit{table constructor}\\
	& | \; e_{1} + e_{2} \;
	| \; e_{1} \; {..} \; e_{2} \;
	| \; e_{1} == e_{2} \;
	| \; e_{1} < e_{2} & \textit{binary operations}\\
	& | \; e_{1} \;\&\; e_{2} \;
	| \; e_{1} \; \mathbf{and} \; e_{2} \;
	| \; e_{1} \; \mathbf{or} \; e_{2} & \textit{binary operations}\\
	& | \; \mathbf{not} \; e \;
	| \; \# \; e & \textit{unary operations} \\
	& | \; \lfloor me \rfloor_{1} & \textit{one result}\\
	l ::= & & \textsc{lvalues:}\\
	& \;\; id_{l} & \textit{variable assignment}\\
	& | \; e_{1}[e_{2}]_{l} & \textit{table assignment}\\
	& | \; id[e] \; {<}V{>} & \textit{type coercion}\\
	k ::= & & \textsc{literals:}\\
	& \;\; \mathbf{false} \; | \;
	\mathbf{true} \; | \;
	{\it int} \; | \;
	{\it float} \; | \;
	{\it string} & \\
	el ::= & & \textsc{expression lists:}\\
	& \;\; \overline{e} \; | \;
	\overline{e}, me & \\
	me ::= & & \textsc{multiple results:}\\
	& \;\; a & \textit{application}\\
	& | \; {...} & \textit{vararg expression}\\
	a ::= & & \textsc{calls:}\\
	& \;\; e(el) & \textit{function call}\\
	& | \; e{:}n(el) & \textit{method call}\\
	f ::= & & \textsc{functions:}\\
	& \;\; \mathbf{fun} \; (pl){:}S \; s \;;\; \mathbf{return} \; el & \\
	pl ::= & & \textsc{parameter lists:}\\
	& \;\; \overline{id{:}F} \; | \;
	\overline{id{:}F},{...}{:}F & \\
	\end{array}
	$$
}
	\caption{Abstract Syntax}
	\label{fig:syntax}
\end{figure}

Figure~\ref{fig:subrec} shows the subtyping rules for
recursive types. Rule {\sc S-Amber} is the \emph{Amber rule}~\cite{cardelli1986amber} for subtyping between
two recursive types. Rules {\sc S-UnfoldRight} and {\sc S-UnfoldLeft} unfold the recursive type for establishing
subtyping between a non-recursive and a recursive type,
or vice-versa.

The dynamic type $\Any$ is only a subtype of itself and of
$\Value$, and no type except $\Any$ is a subtype of $\Any$.
The type $\Any$ interacts with other types through the
{\em consistency} and {\em consistent-subtyping}
relations~\cite{siek2007objects}. We use the symbol $\sim$ for
consistency, and $\lesssim$ for consistent-subtyping.

The type $\Any$ is trivially consistent with all types, and all types
are consistent with $\Any$. A type is also consistent with
itself. Two union types $F_1 \cup F_2$ and $F_3 \cup F_4$ are
consistent if either $F_1 \sim F_3$ and $F_2 \sim F_4$ or
$F_1 \sim F_4$ and $F_2 \sim F_3$. Two function types
$S_1 \rightarrow S_2$ and $S_3 \rightarrow S_4$ are consistent
if and only if $S_3 \sim S_1$ and $S_2 \sim S_4$. Two table types are consistent if and only if they have the same key types, and the value types of each key type are consistent. Two recursive types are consistent if and only if their contents are consistent assuming that their type variables are consistent. Unions of tuple types follow the same rules as unions of first-level types. Variadic types are consistent if and only if their base types are consistent.
Finally, pair types $F_1 \times P_1$ and $F_2 \times P_2$ are
consistent if and only if $F_1 \sim F_2$ and $P_1 \sim P_2$.

In a language with subtyping, the consistency relation is
too restrictive. We need to combine it with subtyping into a
{\em consistent-subtyping} relation. The definition is
straightforward: a type is a consistent-subtype
of another if the first type is a subtype of a type
that is consistent with the other, or if the first type
is consistent with a type that is a subtype of the other.

The implementation of Typed Lua also uses consistent-subtyping to normalize and simplify union types.
For instance, the union type $\Boolean \cup \Any$ simplifies
to $\Any$, because $\Boolean$ is a consistent-subtype
of $\Any$. Another example is the union type
$\Number \cup \Nil \cup 1$, that simplifies to
$\Number \cup \Nil$, because $1$ is a consistent-subtype of $\Number$.

\section{Typing rules}
\label{sec:rules}

\begin{figure*}[t]
{\footnotesize
\[
\begin{array}{c}
\begin{array}{c}
\mylabel{T-Constructor}\\
\dfrac{\begin{array}{c}
	\overline{\env_v, \penv \vdash e_1: F_1, \env_f}
	\;\;\;
\overline{\env_1, \penv \vdash e_2: F_2, \env_v}	\\
	T = \{\overline{F_1{:}vt(F_1,F_2)}\}_{unique} \;\;\;
	\env_{2} = merge(\overline{\env_{f}}) \;\;\; wf(T)
	\end{array}}
{\env_{1}, \penv \vdash \{\;\overline{[e_{1}] = e_{2}}\;\}:T, \env_{2}}
\end{array}
\begin{array}{c}
\mylabel{T-NewFieldUnique}\\
\dfrac{\begin{array}{c}
	\env_{1}(id) = \{ \overline{F:V} \}_{unique}\\
	\env_{1}, \penv \vdash e:F^{new}, \env_{2} \;\;\;
	\overline{F^{new} \not\lesssim F} \;\;\;
	V^{new} = vt(F^{new}, V)
	\end{array}}
{\begin{array}{l}
	\env_{1}, \penv \vdash id[e] {<}V{>}:V^{new},
	\env_{2}[id \mapsto \{ \overline{F{:}V}, F^{new}{:}V^{new}\}_{unique}]
	\end{array}}
\end{array}\\\\
\begin{array}{c}
\mylabel{T-IdRead}\\
\dfrac{\env(id) = F}
{\env, \penv \vdash id:close(F), \env[id \mapsto open(F)]}
\end{array}
\begin{array}{c}
\mylabel{T-IdWrite}\\
\dfrac{\env(id) = F}
{\env, \penv \vdash id_{l}:F, \env}
\end{array}
\begin{array}{c}
\mylabel{T-IndexIdRead}\\
\dfrac{\begin{array}{c}
	\env_{1}(id) = \{\overline{F:V}\} \;\;\;
	\env_{1}, \penv \vdash e_{2}:F^e, \env_{2} \;\;\;
	 F^e \lesssim F_{i}
	\end{array}}
{\env_{1}, \penv \vdash id[e_{2}]:rconst(V_{i}), \env_{2}}
\end{array}
\\ \\
\begin{array}{c}
\mylabel{T-IndexExpRead}\\
\dfrac{\begin{array}{c}
	\env_{1}, \penv \vdash e_{1}:\{\overline{F:V}\}, \env_{2}\\
	\env_{2}, \penv \vdash e_{2}:F^e, \env_{3} \;\;\;
	 F^e \lesssim F_{i}
	\end{array}}
{\env_{1}, \penv \vdash e_{1}[e_{2}]:rconst(V_{i}), \env_{3}}
\end{array}
\begin{array}{c}
\mylabel{T-CoerceClosed}\\
\dfrac{\env(id) \subtype F \;\;\; tag(F,closed)}
{\env, \penv \vdash {<}F{>} \; id:F, \env[id \mapsto reopen(F)]}
\end{array}
\begin{array}{c}
\mylabel{T-CoerceFixed}\\
\dfrac{\env(id) \subtype F \;\;\; tag(F,fixed)}
{\env, \penv \vdash {<}F{>} \; id:F, \env[id \mapsto F]}
\end{array}\\\\
\begin{array}{c}
\mylabel{T-Function}\\
\dfrac{\begin{array}{c}
	closeall(\env_{1})[\overline{id \mapsto F}], \penv[\ret \mapsto S] \vdash s, \env_{2}\\
	\env_{3} = openset(\env_{1}, frv(\mathbf{fun} \; (\overline{id{:}F}){:}S \; s)) \\
	\env_{4} = closeset(\env_{3}, fav(\mathbf{fun} \; (\overline{id{:}F}){:}S \; s))
	\end{array}}
{\env_{1}, \penv \vdash \mathbf{fun} \; (\overline{id{:}F}){:}S \; s:F_1 \times \ldots F_n \times \Void \rightarrow S, \env_{4}}
\end{array}
\begin{array}{c}
\mylabel{T-Local}\\
\dfrac{\begin{array}{c}
	\env_{1}, \penv \vdash el:P, \env_{2} \\
	P \lesssim F_1 \times \ldots \times F_n \times \Value{*} \\
	\env_{2}[\overline{id \mapsto F}], \penv \vdash s, \env_{3}
	\end{array}}
{\env_{1}, \penv \vdash \mathbf{local} \; \overline{id{:}F} = el \; \mathbf{in} \; s, (\env_{3} - \{\overline{id}\})[\overline{id \mapsto \env_2(id)}]}
\end{array}
\end{array}
\]
}
\caption{Typing Rules for Table Types}
\label{fig:tablerules}
\end{figure*}

Figure \ref{fig:syntax} presents the abstract syntax of
Core Typed Lua, a large subset of concrete syntax
that the Typed Lua compiler handles. We use this abstract
syntax in the presentation of the typing rules
for tables and evolution of table types (Section~\ref{sec:tables})
and for functions with overloaded multiple returns and
projection types (Section~\ref{sec:projections}).
Core Typed Lua simplifies the presentation of typing rules
without sacrificing expressiveness.

The main differences between Core Typed Lua and the concrete
syntax are:
\begin{itemize}
\item lack of labels and goto statements, as they are incompatible
with the {\em flow typing} of Typed Lua's type system;
\item local variable declarations have an explicit block,
instead of being just statements;
\item no {\bf elseif} clause in {\bf if} statements;
\item no {\bf repeat} and {\bf for} loops, just {\bf while};
\item the only arithmetic operator is $+$, the only relational
operators are $==$ and $<$, and the only bitwise operator
is $\&$, as all other operators have typing rules identical to
one of these;
\item type coercion for evolution of table types is explicit,
with two coercion terms, the l-value $id[e] \; {<}V{>}$ for adding a field to
a table through assignment, and the r-value ${<}F{>} \;id$ for reinterpreting
a table type to a compatible type that is expected by the context;
\item all function declarations are anonymous, so there is a
statement for recursive declarations;
\item function or method applications that throw away all
results or all but the first result are explicitly annotated
as such, instead this being implicit in their syntactic context;
\item identifiers that appear in l-value position are explicitly
annotated as such with an $l$ subscript.
\end{itemize}

We present the typing rules as a deduction system for two typing relations, one for typing statements and another for typing expressions. Typing judgments for statements have the form $\env_{1}, \penv \vdash s, \env_{2}$, meaning that
given a type environment $\env_{1}$ and a {\em projection environment} $\penv$ we can prove that a statement $s$ produces a new type environment $\env_{2}$. Typing judgments for
expressions have the form $\env_{1}, \penv \vdash e : T, \env_{2}$, meaning that given a type environment $\env_{1}$
and a projection environment $\penv$ we can prove that an expression $e$ has type $T$ and produces a new type environment $\env_{2}$.
Only the most relevant rules are shown. The first author's Ph. D. thesis has the full set of rules~\cite{maidl2015tl}.

The type environment is standard, and maps
identifiers to expression types. Some typing rules of
Section~\ref{sec:tables} can change the type of an identifier,
so the typing relation has both an input and an output type
environment. The {\em projection environment} $\Pi$ maps projection labels to second-level types, and we explain
its use in Section~\ref{sec:projections}.

\subsection{Tables and Evolution of Table Types}
\label{sec:tables}

\begin{figure}
	{\footnotesize
	\[
	\begin{array}{rcl}
	wf(\{\overline{F:V}\}_{u|o|f|c}) & = &
	 \forall i \; ((\nexists j \; i \not= j \,\wedge\, F_{i} \lesssim F_{j}) \,\wedge \\
	 & &  wf(V_{i}) \,\wedge\, \lnot tag(V_{i},unique) \,\wedge\\
	 & &  \lnot tag(V_{i},open))\\
	wf({\bf const}\; F) & = & wf(F) \\
	wf(F_1 \cup F_2) & = & wf(F_1) \,\wedge\, wf(F_2) \\
	wf(\mu x.F) & = & wf(F) \\
	wf(S_1 \rightarrow S_2) & = & wf(S_1) \,\wedge\, wf(S_2) \\
	wf(S_1 \sqcup S_2) & = & wf(S_1) \,\wedge\, wf(S_2)\\
	wf(F{*}) &=& wf(F) \\
	wf(F \times P) &=& wf(F) \,\wedge\,wf(P)\\
	wf(F) & = & \top \;\;\;\mathrm{for\; all\; other\; cases}\\\\
	tag(F_1 \cup F_2, t) & = & tag(F_1, t) \,\vee\, tag(F_2,t) \\
	tag(\{\overline{F:V}\}_t, t) & = & \top\\
	\multicolumn{3}{c}{
		\;\;\;\;\mathrm{other\;recusive\;cases\;are\;similar,\;other\;base\;cases\;are\;}\bot}\\
\\\\
    vt(L, V) & = & fix(V) \\
    vt(F_1, F_2) & = & nil(fix(F_2))\\
    vt(F_1, {\bf const}\;F_2) & = & {\bf const}\;nil(fix(F_2))\\\\
    nil(T) & = & T \;\;\; \mathrm{if}\;\Nil \lesssim T\\
    nil(T) & = & T \cup \Nil \;\;\; \mathrm{otherwise}\\\\
	fix(\{\overline{F:V}\}_{unique|open}) & = &
	\{\overline{F:V}\}_{fixed}\\
	\multicolumn{3}{c}{\mathrm{other\;cases\;by\;straightforward\;structural\;recursion}}
	\end{array}
	\]}
	\caption{Auxiliary Functions for Table Types}
\label{fig:funcs}
\end{figure}

\begin{figure*}
{\footnotesize
\[
\begin{array}{rcl}
	merge(\overline{\env}) & = & reduce(\overline{\env}, merge2)\\
	merge2(\env_1,\env_2) & = & \{\overline{(id,merget(\env_1(id),\env_2(id))}\}\\
	merget(T_1, T_2) & = & T_1 \;\;\; \mathrm{if\;} T_2 \lesssim T_1\\
	merget(T_1, T_2) & = & T_2 \;\;\; \mathrm{if\;} T_1 \lesssim T_2\\
	\multicolumn{3}{c}{\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\mathrm{the\;next\;case\;applies\;if}\;
		\overline{V^l \lesssim_u V_r \,\vee\, V^r \lesssim_u V_l}\;\mathrm{and\;the\;right\; side\; is\;}wf}\\
	merget(\{\overline{F:V^l},\overline{F^{\prime}:V^\prime}\}_{unique},
	\{\overline{F:V^r},\overline{F^{\prime\prime}:V^{\prime\prime}}\}_{unique}) &=&
	\{\overline{F:sup_u(V^l,V^r)},\overline{F^\prime:V^\prime},\overline{F^{\prime\prime}:V^{\prime\prime}}\}_{unique}
	\\
	\multicolumn{3}{c}{\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\mathrm{the\;next\;case\;applies\;if}\;
		\overline{V^l \lesssim_c V_r \,\vee\, V^r \lesssim_c V_l}\;\mathrm{and\;the\;right\; side\; is\;}wf}\\
	merget(\{\overline{F:V^l},\overline{F^{\prime}:V^{\prime}}\}_{unique|open},
	\{\overline{F:V^r},\overline{F^{\prime\prime}:V^{\prime\prime}}\}_{unique|open}) &=&
	\{\overline{F:sup_c(V^l,V^r)},\overline{F^\prime:V^\prime},\overline{F^{\prime\prime}:V^{\prime\prime}}\}_{open}
	\\
	merget(T_1, T_2) & = & \bot \;\;\; \mathrm{otherwise}\\\\
	join(\env_1,\env_2) & = & \{\overline{(id,joint(\env_1(id),\env_2(id))}\}\\
	joint(T_1, T_2) & = & T_1 \;\;\; \mathrm{if\;} T_2 \lesssim T_1\\
	joint(T_1, T_2) & = & T_2 \;\;\; \mathrm{if\;} T_1 \lesssim T_2\\
	\multicolumn{3}{c}{\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\mathrm{the\;next\;case\;applies\;if}\;
		\overline{V^l \lesssim_u V_r \,\vee\, V^r \lesssim_u V_l}\;\mathrm{and\;the\;right\; side\; is\;}wf}\\
	joint(\{\overline{F:V^l},\overline{F^{\prime}:V^{\prime}}\}_{unique},
	\{\overline{F:V^r},\overline{F^{\prime\prime}:V^{\prime\prime}}\}_{unique}) &=&
	\{\overline{F:sup_u(V^l,V^r)},\overline{F^\prime:nil(V^\prime)},\overline{F^{\prime\prime}:nil(V^{\prime\prime})}\}_{unique}\\
	joint(T_1, T_2) & = & \bot \;\;\; \mathrm{otherwise}\\\\
	sup_u(V_1, V_2) \,=\, V_2 \;\;\; \mathrm{if}\; V_1 \lesssim_u V_2 & &
	   sup_u(V_1, V_2) \,=\, V_1 \;\;\; \mathrm{if}\; V_2 \lesssim_u V_1 \\
	\\
	reopen(\{\overline{F:V}\}_{closed}) \,=\, \{\overline{F:V}\}_{open} & &
	  reopen(F) \,=\, F\end{array}
\]}
\caption{Merge and Join Functions}
\label{fig:mergejoin}
\end{figure*}

The simplest expression involving tables is the empty
table constructor $\{\}$. The empty table constructor always
has type $\{\}_{unique}$. A more interesting example is $\{ [``x"] = 1, [``y"] = 2 \}$, which has type $\{ ``x":1 , ``y": 2 \}_{unique}$. The subtyping rule for {\em unique} tables lets
us assign this table to a variable with a more general
type: $\{ ``x":\Number , ``y": \Number \}_{unique}$, or
even $\{ \String:\Number \cup \Nil \}_{unique}$.

Figure~\ref{fig:tablerules} presents the typing rules for table types.
Rule {\sc T-Constructor} is the rule for constructors
like the examples above, that
do not end with an expression that potentially returns
multiple values.
Due to the system for changing the table type of variables that
we will explain in this section, any expression can potentially
change the type environment. Lua semantics does not dictate
an order of evaluation among the pairs of field initializers,
so all of them are typed in the same input type environment.

The $merge$ auxiliary function then combines output
environments, diverging in case of conflicting changes.
Fields can always be added to {\em unique} and {\em open}
tables in one environment but not the other. Two environments
can add a field with the same key, as long as they have
the same type or one is a supertype of the other, respecting
any restrictions with regards to depth subtyping that the table may have.

Rule {\sc T-Constructor} also checks if the resulting type is {\em well-formed} with the predicate $wf$. Checking for well-formedness avoids ambiguous table types. An example of ambiguous table type is the type
$\{1:\Number, \Integer:\String, \Any:\Boolean\}$,
where indexing it with a key of type $\Integer$ could
yield either a number, a string or a boolean at runtime.

Well-formed table types also do not allow \emph{unique} and
\emph{open} table types to appear in the type of the values.
At the moment, local variables are the only kind of reference that the system
can track, so this restriction is
necessary. This limitation of the type system is the reason why the {\sc T-Constructor} rule uses the auxiliary function $fix$
(in the definition of $vt$)
 to change any {\em open} and {\em unique} table types used in the field initializer to {\em fixed}. As an example, the table constructor $\{[``x"] = 1, [``y"] = \{[``z"] = 2\}\}$
has type $\{``x":1, ``y":\{``z":2\}_{fixed}\}_{unique}$.

There are two ways the type of {\em unique} and {\em open} tables can change in Typed
Lua. The first way is by assignment to a non-existing
field. Let us go back to the example shown in Figure~\ref{fig:newpoint}. Assuming that the type of the
$x$ and $y$ is $\Number$, we can translate the first three lines
of function {\tt new\_point} to the abstract syntax of Figure~\ref{fig:syntax}:
{\footnotesize
\begin{center}
\begin{tabular}{ll}
\multicolumn{2}{l}{$\mathbf{local} \; point: \{\}_{unique} = \{\} \; \mathbf{in}$}\\
& \multicolumn{1}{l}{$point[``x"] \; {<}\Number{>} = x;\;
point[``y"] \; {<}\Number{>} = y$}
\end{tabular}
\end{center}
}

The expressions on the left-side of the assignment are type
coercion l-values, and their type-checking is responsible
for changing the type of $point$. The type annotations in
these expressions are not
required in actual Typed Lua code, as the compiler infers the types from the corresponding expression on the right side.

Rule {\sc T-NewFieldUnique} typechecks coercion l-values on
{\em unique} table types, guaranteeing that the new type
is still well-formed. In the example above, the left
side of the first assignment changes the type of $point$
to $\{``x":\Number\}_{unique}$. The rest of the assignment
typechecks, as the right-hand side has type $\Number$.
The second assignment changes the type of $point$ to
$\{``x":\Number, ``y": \Number\}_{unique}$.

We could add both fields with a single assignment statement,
as in the following example:
{\footnotesize
\begin{center}
	\begin{tabular}{ll}
		\multicolumn{2}{l}{$\mathbf{local} \; point: \{\}_{unique} = \{\} \; \mathbf{in}$}\\
		& \multicolumn{1}{l}{$point[``x"] \; {<}\Number{>},point[``y"] \; {<}\Number{>} = x,y;$}
	\end{tabular}
\end{center}
}
In this case, the first coercion expression would still change the type of $point$ to $\{``x":\Number\}_{unique}$, but the
second would change it to $\{``y":\Number\}_{unique}$.
Merging the two yields $\{``x":\Number, ``y": \Number\}_{unique}$
through the third case of function $merget$ defined in Figure~\ref{fig:funcs}.

Open tables have a rule {\sc T-NewFieldOpen} that is not shown
in Figure~\ref{fig:tablerules} due to brevity. The only thing that
changes from one rule to the other is the tag in the type of $id$.
There are analogous rules for adding methods to {\em unique}
and {\em open tables} as a side-effect of typechecking a method declaration.

The type system needs to track aliasing of tables,
as the flexibility of {\em unique} and {\em open} tables
depend on respectively having no aliases and having only {\em closed} aliases. The system conservatively assumes that
a table has been aliased if its identifier appears in r-value position, with a couple of exceptions which we will explain shortly.

Rule {\sc T-IdRead} is responsible for tracking
aliasing. Its auxiliary function $close$ is similar to
function $fix$ defined in Figure~\ref{fig:funcs},
except that it changes the tag of {\em unique} or
{\em open} tables to {\em closed}. Its purpose
is to construct a {\em closed} type for the alias,
if necessary. Its auxiliary function $open$ is similar
to $fix$ and $close$, except that it changes the type of
{\em unique} tables to {\em open}. Its purpose
is to track the fact that an $id$ now has an alias,
if necessary.

Consider the following example, where we make an alias
of an {\em unique} table:
{\footnotesize
\begin{center}
\begin{tabular}{lll}
\multicolumn{3}{l}{$\mathbf{local} \; a:\{\}_{unique} = \{\} \; \mathbf{in}$}\\
& \multicolumn{2}{l}{$\mathbf{local} \; b:\{\}_{closed} = a \; \mathbf{in}\;\;a[``x"] \; {<}\String{>} = ``foo";$}
\end{tabular}
\end{center}
}

This example typechecks; after the initialization of $b$
the type of $a$ is {\em open} instead of {\em unique}, but
this still lets the assignment add a new field to $a$.
If we changed the tag of the type annotation of $b$ to
any other tag the example would not typecheck anymore,
as the type of expression $a$ is $\{\}_{closed}$.

If we did not change the tag on the type produced by $a$
we could break type safety, as we could declare $b$ with
tag {\em unique} or {\em open} and add fields that would
conflict with the type of the fields in $a$, but at
runtime both reference the same table.

It is not a problem for an {\em unique} or {\em open}
table to appear as an l-value, because {\sc T-IdRead} is
sufficient to forbid the creation of an alias to another
{\em unique} or {\em open} table. For this reason,
identifiers that appear as l-values have their own rule
{\sc T-IdWrite}.

Another use of the identifier that does not create an
alias is when indexing the table. Rule {\sc T-IndexIdRead}
covers this case (function $rconst$ just strips the {\bf const} qualifier from the value type, if present). For comparison, rule {\sc T-IndexExpRead}
applies for indexing expressions where the expression
denoting the table is not an identifier. The rules for
indexing expressions in l-value position are similar,
except to make sure that the field is not {\bf const} .

A second way of changing a table type is by a
{\em coercion expression}. Coercion expressions let
an {\em unique} or {\em open} table be used in a context
that expects a table type with a different shape.
Coercion expressions always create an alias, so
the type produced by the coercion is always
{\em closed} or {\em fixed}. If the coercion is to a
{\em closed} table type the type of the table changes
to an {\em open} type with the same shape, but if
the coercion is to a {\em fixed} type the table has
to assume the same type.

Rules {\sc T-CoerceClosed} and {\sc T-CoerceFixed} type
coercion expressions ${<}F{>} \; id$.
As with coercion l-values, the Typed Lua compiler automatically
infers the type $F$, so to the programmer a coercion
expression looks just like an ordinary use of the table.
Notice that the type of $id$ after {\sc T-CoerceClosed} will be an {\em open} type
only if $F$ is a plain {\em closed} table type.
Coercion is only possible towards a supertype, although
we have seen in Section~\ref{sec:subtyping} that the lack
of aliases makes the subtyping relation of {\em unique}
very flexible.

In the example below, we use a coercion expression to
widen the type of a field in an {\em unique}
table, and then add another field, to show that the
table is now {\em open}:
{\footnotesize
\begin{center}
\begin{tabular}{llll}
\multicolumn{4}{l}{$\mathbf{local} \; a:\{\}_{unique} = \{ \} \; \mathbf{in}$}\\
& \multicolumn{3}{l}{$a[``x"] \; {<}\String{>} = ``foo";\;
a[``y"] \; {<}\String{>} = ``bar";$}\\
& \multicolumn{3}{l}{$\mathbf{local} \; b:\{``x":\String, ``y":\String \cup \Nil \}_{closed} =$}\\
& & \multicolumn{2}{l}{${<}\{``x":\String, ``y":\String \cup \Nil\}_{closed}{>} \; a \; \mathbf{in}$}\\
& & & \multicolumn{1}{l}{$a[``z"] \; {<}\Integer{>} = 1$}
\end{tabular}
\end{center}
}

The type of $a$ by the time of the inner {\bf local} block
is $\{``x":\String, ``y":\String\}_{unique}$. This type is
a subtype of $\{``x":\String, ``y":\String\cup\Nil\}_{closed}$, as {\em unique} tables
have depth subtyping even in non-{\bf const} fields.
The coercion expression and the initialization of $b$
typecheck, and the type of $a$ changes to
$\{``x":\String, ``y":\String\cup\Nil\}_{open}$.
As the type is {\em open}, we can continue adding fields
to it, but are now restricted on future coercions. For
example, we will not be able to widen the type of $``x"$
to $\String \cup \Nil$, as that could break type safety
(by writing $\Nil$ to $``x"$ using reference $a$, and reading
$``x"$ using the alias $b$).

Lua has first-class functions, so another way of aliasing
{\em unique} and {\em open} references is by closing
over them in a function body. In the environment used for
typing the function body, all {\em unique} and {\em open}
tables are {\em closed} with the auxiliary function $closeall$.
Assignment to a closed-over table can be unsafe, because the {\em reference} to it is aliased as well. In the following
example, assume that $g$ receives a parameter of type
$\{ ``x": \String \cup \Nil\}_{closed}$:
{\footnotesize
\begin{center}
	\begin{tabular}{llll}
		\multicolumn{4}{l}{$\mathbf{local} \; a:\{\}_{open}
			= \{\} \; \mathbf{in}$}\\
		& \multicolumn{3}{l}{$\mathbf{local} \; f:\Void \rightarrow \Void =\;\mathbf{fun} \; ():\Void\;\;\;
		 a = \{[``x"]=5\} $}\\
		& & \multicolumn{2}{l}{$\mathbf{in} \; \lfloor g({<}\{``x":
			 \String \cup \Nil\}_{closed}{>} \; a) \rfloor_{0}$}
	\end{tabular}
\end{center}
}

The type of $a$ on line 2 is $\{\}_{closed}$, so the assignment
would type-check. But then the function call on the last line
would also type-check, as $\{\}_{open}$ can be coerced to
$\{ ``x": \String \cup \Nil\}$. A solution is to change the
type of $a$ from {\em open} to {\em closed} after the function
declaration. In order to do that, we use the auxiliary function
$fav$ ({\em free assigned-to variables}) to collect this
set of identifiers, and then function $closeset$ changes
the type environment to so any of these variables that
has an {\em unique} or {\em open} table type becomes {\em closed}.

Closed-over variables that are not assigned still may
change their type if they have an {\em unique} table type
and are aliased inside the function body. We use the auxiliary
function $frv$ ({\em free referenced variables}) to collect
this set, and then function $openset$ changes any variables
with an {\em unique} table type in the environment to {\em open}.

Rule {\sc T-Function} types non-variadic function declarations,
and shows how these auxiliary functions work together.
Notice that the environment $\env_{2}$ resulting from
typing the function body is just ignored. The rule for
declaring variadic functions and recursive functions are
similar. Functions $closeall$, $closeset$, $openset$, $fav$,
and $frv$ are straightforward, and were omitted for brevity.

The following example typechecks, and uses all the parts of {\sc T-Function}:
{\footnotesize
\begin{center}
\begin{tabular}{llll}
\multicolumn{4}{l}{$\mathbf{local} \; a:\{\}_{unique}, b:\{\}_{unique} = \{\}, \{\} \; \mathbf{in}$}\\
& \multicolumn{3}{l}{$\mathbf{local} \; f:\Integer \times \Void \rightarrow \Integer \times \Void =$}\\
& & \multicolumn{2}{l}{$\mathbf{fun} \; (x:\Integer):\Integer \times \Void$}\\
& & & \multicolumn{1}{l}{$b = a \;;\; \mathbf{return} \; x + 1$}\\
& \multicolumn{3}{l}{$\mathbf{in} \; a[``x"] \; {<}\Integer{>} = 1 \;;\; \lfloor f(a[``x"]) \rfloor_0$}\\
\end{tabular}
\end{center}
}

The assignment $b=a$ typechecks because, at that point,
both $b$ and $a$ have type $\{\}_{closed}$ due to $closeall$.
The set $fav$ is $\{b\}$, and the set $frv$ is $\{a\}$.
This causes the type of $b$ to also be $\{\}_{closed}$
in the body of the inner {\bf local} statement, due to $closeset$, and the type of $a$ to be $\{\}_{open}$ due
to $openset$. Being $\{\}_{open}$, adding a new field
is allowed, changing the type of $a$ to $\{``x": \Integer\}_{open}$ after the last semicolon. After the call to
$f$, the variable $b$ is an alias to $a$ but this is not
an issue, as $\{\}_{closed}$ is a supertype of $\{``x": \Integer\}_{open}$.

\subsection{Projection Types}
\label{sec:projections}

\begin{figure*}[t]
{\footnotesize
\label{fig:projtypes}
\[
\begin{array}{c}
\begin{array}{c}
\mylabel{T-LocalProj}\\
\dfrac{\begin{array}{c}
	\env_{1}, \penv \vdash el:E, \env_{2}, (x,S)\\
	\env_{3} = \env_{2}[id_{1} \mapsto proj(E, 1), \ldots, id_{n} \mapsto proj(E, n)]\\
	\env_{3}, \penv[x \mapsto S] \vdash s, \env_{4} \;\;\;
	n = |\;\overline{id}\;|
	\end{array}}
{\env_{1}, \penv \vdash \mathbf{local} \; \overline{id} = el \; \mathbf{in} \; s, (\env_{4}-\{\overline{id}\})[\overline{id \mapsto \env_2(id)}]}
\end{array}
\begin{array}{c}
\mylabel{T-ExpListProj}\\
\dfrac{\begin{array}{c}
	\env_{1}, \penv \vdash e_{i}:F_{i}, \env_{i+1} \;\;\;
	\env_{1}, \penv \vdash me:S, \env_{n+2} \;\;\; n=|\overline{e}|\\
	S = S_1 \sqcup S_2 \;\;\;m = max(|S_1|, |S_2|) \;\;\; x \notin \Pi\\
	\env_{f} = merge(\env_{1}, ..., \env_{n+2})
	\end{array}}
{\env_{1}, \penv \vdash \overline{e},me:}\\ {F_{1} \times ... \times F_{n} \times \pi_{1}^{x} \times ... \times \pi_{m}^{x}{*}, \env_{f}, (x,S)}
\end{array}\\\\
\begin{array}{c}
\mylabel{T-IfFilterProjThen}\\
\dfrac{\begin{array}{c}
	\env_{1}(id) = \pi_{i}^{x} \\ S_t = fonilpt(\Pi(x), i)\\
	finil(proj(\Pi(x), i)) = {\bf void} \\
	\env_{1}, \penv[x \mapsto S_t] \vdash s_{1}, \env_{2}
	\end{array}}
{\env_{1}, \penv \vdash \mathbf{if} \; id \; \mathbf{then} \; s_{1} \; \mathbf{else} \; s_{2}, \env_{2}}
\end{array}
\begin{array}{c}
\mylabel{T-IfFilterProjElse}\\
\dfrac{\begin{array}{c}
	\env_{1}(id) = \pi_{i}^{x} \\
	 S_e = finilpt(\Pi(x), i)\\
	fonil(proj(\Pi(x), i)) = {\bf void} \\
	\env_{1}, \penv[x \mapsto S_e] \vdash s_{2}, \env_{2}
	\end{array}}
{\env_{1}, \penv \vdash \mathbf{if} \; id \; \mathbf{then} \; s_{1} \; \mathbf{else} \; s_{2}, \env_{2}}
\end{array}
\begin{array}{c}
\mylabel{T-IfFilterProjBoth}\\
\dfrac{\begin{array}{c}
	\env_{1}(id) = \pi_{i}^{x} \\ S_t = fonilpt(\Pi(x), i) \; S_e = finilpt(\Pi(x), i)\\
	\env_{1}, \penv[x \mapsto S_t] \vdash s_{1}, \env_{2} \\
	\env_{1}, \penv[x \mapsto S_e] \vdash s_{2}, \env_{3} \\
	\env_{4} = join(\env_{2}, \env_{3})
	\end{array}}
{\env_{1}, \penv \vdash \mathbf{if} \; id \; \mathbf{then} \; s_{1} \; \mathbf{else} \; s_{2}, \env_{4}}
\end{array}
\end{array}
\]}
\caption{Rules for Projection Types}
\end{figure*}

\begin{figure}[t]
{\scriptsize
\label{fig:projtypes}
\[
\begin{array}{c}
\begin{array}{rcl}
fonilpt(P_1 \sqcup P_2, i) & = & P_2 \;\; \mathrm{if} \; fonil(proj(P_1, i)) = {\bf void} \\
fonilpt(P_1 \sqcup P_2, i) & = & P_1 \;\; \mathrm{if} \; fonil(proj(P_2, i)) = {\bf void} \\
fonilpt(P_1 \sqcup P_2, i) & = & P_1 \sqcup P_2 \;\; \mathrm{otherwise}\\
fonilpt(P \sqcup S, i) & = & fonilpt(S,i) \;\; \mathrm{if} \; fonil(proj(P, i)) = {\bf void} \\
fonilpt(P \sqcup S, i) & = & P \sqcup fonilpt(S,i) \;\; \mathrm{otherwise}\\
fonilpt(S \sqcup P_2, i) & = & fonilpt(S,i) \;\; \mathrm{if} \; fonil(proj(P, i)) = {\bf void} \\
fonilpt(S \sqcup P, i) & = & fonilpt(S,i) \sqcup P \;\; \mathrm{otherwise}\\
fonilpt(S_1 \sqcup S_2, i) & = & fonilpt(S_1,i) \sqcup fonilpt(S_2,i)
\end{array}\\\\
\begin{array}{rcl}
fonil(F_1 \cup F_2) & = & fonil(F_1) \;\; \mathrm{if}\;fonil(F_2) = {\bf void}\\
fonil(F_1 \cup F_2) & = & fonil(F_2) \;\; \mathrm{if}\;fonil(F_1) = {\bf void}\\
fonil(F_1 \cup F_2) & = & fonil(F_1) \cup fonil(F_2) \;\; \mathrm{otherwise}\\
%\multicolumn{4}{c}{\mathrm{the\;next\;two\;cases\;apply\;if\;}F
%	\;\mathrm{is\;not\;a\;union}}\\
fonil(F) & = & {\bf void} \;\; \mathrm{if} \; F \subtype \Nil \; \mathrm{and} \; \Nil \subtype F\\
fonil(F) & = & F \;\; \mathrm{otherwise}
\end{array}
\end{array}
\]}
\caption{Auxiliary Functions for Projection Types}
\end{figure}

As we have seen in Section~\ref{sec:statistics}, Lua
programmers often overload the return type of functions
to denote errors, returning a {\tt nil} result and
an error message in case of an error instead of the
usual return values.

As an example, consider again the {\tt idiv} function
from Figure~\ref{fig:over}, which returns the quotient and rest of integer division, or a division by zero error. In Typed Lua, we can give a return type $(\Integer \times \Integer \times \Nil*) \sqcup (\Nil \times \String \times \Nil{*})$ to that function.

As is also shown in Figure~\ref{fig:over}, the idiom for using such
a function is to test the first returned value. We
can translate that code to the abstract syntax of
Figure~\ref{fig:syntax}, leaving placeholders for
the body of the {\bf then} and {\bf else} branches:
{\footnotesize
\begin{center}
	\begin{tabular}{ll}
		\multicolumn{2}{l}{$\mathbf{local} \, q, r = idiv(a, b) \, \mathbf{in} \, \mathbf{if} \, q \, \mathbf{then} \, s_1 \, \mathbf{else} \, s_2$}
	\end{tabular}
\end{center}
}

A standard way of decomposing the union in the assignment
would let the type of $q$ be $\Integer \times \Nil$ and
the type of $r$ be $\Integer \times \String$. Flow typing
would narrow the type of $q$ to $\Integer$ in the {\bf then}
branch and to $\Nil$ in the {\bf else} branch, but would
leave the type of $r$ unchanged.

{\em Projection types}
are a general way to make the dependency between the types
of $q$ and $r$ survive the decomposition of the tuple,
so flow typing can narrow all of the components by testing
just one of them.

Intuitively, a projection type $\pi_{i}^{x}$ denotes the union of
the i-th components of all the tuples in the union of tuple types
denoted by the label $x$. Unions of tuple types referenced by projections are kept in their own {\em projection environment} $\Pi$. A fresh label is generated whenever the last term
in an expression list has an union of tuple types as its type.
Figure~\ref{fig:projtypes} presents the rules for introducing and filtering projection types.

Notice that in the above example the local variables $q$ and $r$ are declared without an explicit type.
 The rule for typing this {\bf local} statement,
{\sc T-LocalProj}, introduces a new label in the projection
environment used for typing the {\bf if} statement.

The first judgment above the bar of rule {\sc T-LocalProj} uses the auxiliary typing relation $\env_{1}, \penv \vdash el : E, \env_{2}, (x,S)$. Rule {\sc T-ExpListProj} is the typing rule for this auxiliary
relation. It does the work of generating a fresh projection label,
and projection types associated with it, if the last term of
the expression list has a union of tuple types as its type.
The rule generates as many projection types as the the length
of the longest tuple.

In the $idiv$ example above, the combination of these two rules binds $x$ to
$(\Integer \times \Integer \times \Nil{*}) \sqcup (\Nil \times \String \times \Nil{*})$ in the projection environment $\Pi$,
and $q$ and $r$ respectively to $\pi_{1}^{x}$ and $\pi_{2}^{x}$
in the type environment used for typing the {\bf if} statement.

At this point, using $q$ or $r$ as an r-value will project
their types into either $\Integer \cup \Nil$ or $\Integer \cup \String$ via rule {\sc T-IdReadProj}, which just uses auxiliary function $proj$. The more interesting cases are inside the
branches of the {\bf if} statement, where rule {\sc T-IfFilterNilProj} filters the whole union of tuples referenced
by the projection type.

Rule \textsc{T-IfFilterProjBoth} uses the auxiliary functions \emph{fonilpt} ({\em filter-out nil in projection type}) and \emph{finilpt} ({\em filter-in nil in projection type}) to
filter the union referenced by $\pi_{i}^{x}$, respectively
filtering $\Nil$ out at every i-th component (removing
the entire tuple if it is $\Nil$) and filtering $\Nil$ in at every i-th component (removing the entire tuple if it is not $\Nil$). These functions respectively use the functions $fonil$ and $finil$ to filter regular unions, plus $proj$ to test projected components. The definitions of $finilpt$ and $finil$ are analogous to the definitions of $fonilpt$ and $fonil$.

Rule {\sc T-IfFilterProjBoth} also uses the auxiliary function $join$ defined in Figure~\ref{fig:funcs} to try to combine the environments that result from typing the two branches. In a $join$ only one environment is guaranteed to be from code that has been executed.

In our example, variable $x$ would be bound to $\Integer \times \Integer \times \Nil{*}$ inside the {\bf then} branch, and bound
to $\Nil \times \String \times \Nil{*}$ inside the {\bf else}
branch. Now $q$ and $r$ project to $\Integer$ and $\Integer$
in the {\bf then} branch, and to $\Nil$ and $\String$ in the
{\bf else} branch.

Rules {\sc T-IfFilterProjThen} and {\sc T-IfFilterProjElse}
respectively cover the case where the {\bf else} branch is unreachable and the case where the {\bf then} branch is unreachable, because either the projected type of $\pi_i^x$
is not a supertype of $\Nil$ or is $\Nil$.

Assignment to an l-value with a projection type is forbidden
(there is no rule {\sc T-IdWriteProj}). Allowing assignment is unsound, as it can break the dependency among the components of the union. In the example below,
the projected type of $r$ outside of the {\bf if} statement
is $\Integer \cup \String$, so the assignment seems correct,
but inside $s_1$ the projected type of $r$ would still be
$\Integer$:
{\footnotesize
\begin{center}
	\begin{tabular}{ll}
		\multicolumn{2}{l}{$\mathbf{local} \, q, r = idiv(a, b) \, \mathbf{in}\; r = ``foo" ;\; \mathbf{if} \, q \, \mathbf{then} \, s_1 \, \mathbf{else} \, s_2$}
	\end{tabular}
\end{center}
}

\section{Related Work}
\label{sec:related}

Tidal Lock~\cite{tidallock} is a prototype of another optional type system for Lua. It covers just a small subset of Lua
in its current form. Its most remarkable feature is
how it structures its table types to support a form of type
evolution through imperative assignment. Typed Lua uses
the same general idea of letting the type of a table evolve
through assignment, but the structure of both the table types
and the typing rules that support this are completely different.

Sol~\cite{sol} is another experimental optional type system
for Lua. While it has some similarities to Typed Lua, it
has more limited table types: Sol tables can only be lists,
maps, and objects that follow a specific object-oriented
idiom that Sol introduces. There is no evolution of table
types.

Lua Analyzer~\cite{luaanalyzer} is another optional type
system for Lua that is specially designed to work with
Löve Studio, an IDE for game development using Lua.
It is unsound by design, and primarily for supporting
IDE autocompletion. There is no evolution of table types.

Typed Racket~\cite{tobin-hochstadt2008ts} is a statically typed version of the Racket language, which is a Scheme dialect.
The main purpose of Typed Racket is to allow programmers to combine untyped modules, which are written in Racket, with typed modules, which are written in Typed Racket. Typed Racket tracks
values that cross the boundary between the typed and
untyped parts to be able to correctly assign blame to type
errors that occur in the typed parts, so is a gradual type
system.

Typed Racket introduced {\em occurrence typing}, a form of
flow typing~\cite{tobin-hochstadt2010ltu}, where type
predicates are used to refining union types.
As this use of type predicates is common in other
dynamically-typed languages, related systems
have appeared~\cite{guha2011tlc,winther2011gtp,pearce2013ccf}.

Gradualtalk~\cite{allende2013gts} is a Smalltalk dialect
with a gradual type system. Its type system combines
nominal and structural typing.
It includes function types, union types, structural object types,
nominal object types types, a self type, and parametric polymorphism. Like Typed Lua, Gradualtalk formalizes the
interaction between typed and untyped code with consistent-subtyping. Due to the performance impact of
the runtime checks that ensure the gradual typing guarantees,
Gradualtalk can be downgraded into an optional type system
through a configuration switch~\cite{allende2013cis}.

Reticulated Python~\cite{vitousek2014deg} is a
gradual type system for Python. It is structural, based on subtyping, and includes list types,
dictionary types, tuple types, function types, set types,
object types, class types, and recursive types.
Besides static type checking, Reticulated Python also introduces
three different approaches for inserting runtime assertions
that preserve the gradual typing guarantee.

Several dynamically typed languages now have optional
type systems: Clojure~\cite{bonnaire-sergeant2015typed-clojure},
JavaScript, Python~\cite{mypy},
and PHP. While Lua has some similarities to
all of these languages, none of these optional type
systems have the features described in this paper.
Most of these languages do not have idioms
that inspired these features; JavaScript has the
idiom of adding fields to an initially empty
record through assignment, but TypeScript sidesteps
the issue by having allowing an empty record to
have any record or object type, as the type of
missing fields is the bottom type of its type system.

Grace~\cite{black2013sg} and Dart are
two languages that have been designed from scratch
to have an optional type system, instead of being
existing dynamically typed languages with a retrofitted
type system.

\section{Conclusions}
\label{sec:conclusion}

We have presented a formalization of Typed Lua,
an optional type system for Lua, with a focus on rules
for two novel features of the system that type unusual
idioms present in Lua programs.

In the first idiom, records and objects are
defined through assignment to an initially empty
table. In Typed Lua's type system the type of a
table can change, either by assignment
or by using the table in a context that expects
a different (but compatible) type from its current one.
The system tracks aliasing of tables
in order to do this type evolution in a type-safe
way.

In the second idiom, a function that can return different
kinds of tuples of return values (for example, one
tuple for its usual path, another for error conditions)
is modeled by having an union of tuple types as its return
type. A destructuring assignment on a union of tuple types
decomposes the tuple in a way that the dependencies between
the types of each member of the union can be tracked.
Narrowing the type of one of the tuple's components with
a type predicate can narrow the types of the other
components.

Usability has been a concern in the design of Typed Lua since the beginning. We realized that a design based solely on what
is possible by the semantics of Lua could lead to a
complex type system. For this reason, we surveyed a large
corpus of Lua code to identify important idioms that
our type system should support.

We performed several
case studies to evaluate how successful we were in our goal of
providing an usable type system.
We evaluated 29 modules from 8 different case studies,
and we could give precise static types to 83\% of the 449
values that these modules export.
For half of the modules, we could give precise static types to
at least 89\% of the exports from each module. The methodology,
detailed results and analysis of this evaluation is part
of the first author's Ph. D. thesis~\cite{maidl2015tl}.

Our evaluation results show that our type system can statically
type check several Lua idioms and features, though the evaluation
also exposed several limitations.
We found that the three main limitations are the lack of
full support for overloaded functions, parametric polymorphism,
and operator overloading.
Overcoming these limitations is one major target for future work,
as it will allow us to statically type check more programs.

Unlike some optional type systems, such as the type systems
of the TypeScript and Dart languages, we designed Typed Lua without deliberately unsound parts.
However, we still do not have proofs that the novel features of
our type system are sound. We are working on a generalization
of the typing rules for evolution of table types where tagged
types can be attached to arbitrary references instead of
just local variables, and expect that a proof of soundness
will come out of this effort.

Typed Lua has a working implementation\footnote{Available at
\url{https://github.com/andremm/typedlua}.}
that Lua programmers can already use as a framework to
document, test, and structure their applications.
Even applications where a full conversion to static
type checking is unfeasible in the current state
of the type system, or too much work,
Lua programmers can still use Typed Lua to document the
external interfaces of their libraries, giving the benefits of static typing
checking to the users of those libraries.

We already have feedback from Lua projects
that are evaluating the use of Typed Lua, such
as the LuaRocks package manager, which is a key
piece of infrastructure for the Lua library ecosystem,
and ZeroBrane Studio, an IDE for Lua programs that is itself
written in Lua.

\acks

The authors thank the anonymous reviewers for their feedback.
Work on Typed Lua has been supported by grants from Google
Summer of Code as well as CAPES and CNPq, two Brazilian Research Councils.

\bibliographystyle{abbrvnat}
\bibliography{paper}

\end{document}


\documentclass{report}
\usepackage[style = numeric, backend = biber]{biblatex}
\usepackage{graphicx, paralist, listings, fancybox, geometry, caption, floatrow, xcolor, color, colortbl, fancyhdr, amsmath, mathtools}
\usepackage{fouriernc}
\usepackage[T1]{fontenc}
\geometry{a4paper, top = 15mm, left = 5mm, right = 5mm, bottom = 17mm}
\fancypagestyle{plain}{
\fancyhead[L]{\texttt{GAME-DA} documentation}
\fancyhead[R]{\textsc{\texttt{GAME-DA} development team}}
\fancyfoot[C]{\thepage}
\addtolength\footskip{12pt}}
\definecolor{table_green}{rgb}{0, 0.6, 0}
\title{\texttt{GAME-DA} Documentation}
\author{\texttt{GAME-DA} Development Team}
\date{}
\newcommand{\md}[1]{\frac{D#1}{Dt}}
\newcommand{\omegabi}{\text{{\osgbi ω}}}
\newcommand{\mubi}{\text{{\osgbi μ}}}
\newcommand{\sigmabi}{\text{{\osgbi σ}}}
\newcommand{\epsilonbi}{\text{{\osgbi ϵ}}}
\newcommand{\etabi}{\text{{\osgbi η}}}
\newcommand{\zetabi}{\text{{\osgbi ζ}}}
\addbibresource{references.bib}
\DeclareFieldFormat[article]{title}{{#1}}

\begin{document}

\maketitle

\tableofcontents

\chapter{Introduction}
\label{sec:introduction}

\texttt{GAME-DA} provides \textit{data assimilation (DA)} funcitonality for the \texttt{GAME} model. The theoretical derivations are presented in \cite{kompendium}. This documentation contains the technical details of the implementations of the data assimilation algorithms. Three different methods of DA are implemented in GAME-DA:
%
\begin{itemize}
\item optimum interplation (OI)
\item three-dimensional variational data assimilation (3D-Var)
\item four-dimensional variational data assimilation (4D-Var)
\end{itemize}
%
Depending on the resolution and the type and amount of observations, certain methods are more suitable than others.

In any of the three cases, the basic workflow is as follows:
%
\begin{enumerate}
\item Downloading the observations. This is done by the bash scripts residing in the directory \texttt{obs\_collector}.
\item Bringing the observations into a standardized format. This is done by the separate executable \texttt{formatter} residing in the directory of the same name.
\item Executing the data assimilation itself, resulting in an input file for the model.
\end{enumerate}

\chapter{Optimum interpolation}
\label{chap:optimum_interpolation}

Let $M \geq 1$ be the number of degrees of freedom of the model, $N \geq 1$ the number of observations, $\mathbf{h} \in \mathbb{R}^N$ the observations as reconstructed from the background state, $\mathbf{y} \in \mathbb{R}^N$ the actual observations, $\overleftrightarrow{H} \in \mathbb{R}^{N\times M}$ the Jacobian of the observations operator, $\overleftrightarrow{B} \in \mathbb{R}^{M\times M}$ the background error covariance matrix and $\overleftrightarrow{R} \in \mathbb{R}^{N\times N}$ the observations error covariance matrix. $\overleftrightarrow{R}$ is usually assumed to be diagonal, which is an excellent approximation if the observation erros are of statistical nature. This does not lead to useful simplifications, however.

It is
%
\begin{align}
\left(\overleftrightarrow{H}\overleftrightarrow{B}\right)_{i, j} &= \sum_{k = 1}^{M}\overleftrightarrow{H}_{i, k}\overleftrightarrow{B}_{k, j}.
\end{align}
%
For $\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T$, one obtains
%
\begin{align}
\left(\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T\right)_{i, j} &= \left[\left(\overleftrightarrow{H}\overleftrightarrow{B}\right)\overleftrightarrow{H}^T\right]_{i, j} = \sum_{k = 1}^{M}\left(\overleftrightarrow{H}\overleftrightarrow{B}\right)_{i, k}\overleftrightarrow{H}^T_{k, j} = \sum_{k = 1}^{M}\left(\overleftrightarrow{H}\overleftrightarrow{B}\right)_{i, k}\overleftrightarrow{H}_{j, k} = \sum_{k = 1}^{M}\left(\sum_{l = 1}^{M}\overleftrightarrow{H}_{i, l}\overleftrightarrow{B}_{l, k}\right)\overleftrightarrow{H}_{j, k} = \sum_{k, l = 1}^M\overleftrightarrow{H}_{i, l}\overleftrightarrow{B}_{l, k}\overleftrightarrow{H}_{j, k}.
\end{align}
%
For the final result, we obtain
%
\begin{align}
x_i &= x_{B, i} + \sum_{j = 1}^N\left[\overleftrightarrow{B}\overleftrightarrow{H}^T\left(\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T + \overleftrightarrow{R}\right)^{-1}\right]_{i, j}\left(y_j - h_j\right) = x_{B, i} + \sum_{j = 1}^N\left[\sum_{k = 1}^N\left(\overleftrightarrow{B}\overleftrightarrow{H}^T\right)_{i, k}\left(\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T + \overleftrightarrow{R}\right)^{-1}_{k, j}\right]\left(y_j - h_j\right)\nonumber\\
&= x_{B, i} + \sum_{j = 1}^N\left[\sum_{k = 1}^N\left(\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T + \overleftrightarrow{R}\right)^{-1}_{k, j}\left(\overleftrightarrow{B}\overleftrightarrow{H}^T\right)_{i, k}\right]\left(y_j - h_j\right) = x_{B, i} + \sum_{j = 1}^N\left[\sum_{k = 1}^N\left(\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T + \overleftrightarrow{R}\right)^{-1}_{k, j}\left(\sum_{l = 1}^M\overleftrightarrow{B}_{i, l}\overleftrightarrow{H}^T_{l, k}\right)\right]\left(y_j - h_j\right)\nonumber
\end{align}
\begin{center}
\doublebox{\parbox{0.8\textwidth}{
\begin{center}
\begin{align}
\Rightarrow x_i &= x_{B, i} + \sum_{j = 1}^N\left[\sum_{k = 1}^N\left(\overleftrightarrow{H}\overleftrightarrow{B}\overleftrightarrow{H}^T + \overleftrightarrow{R}\right)^{-1}_{k, j}\left(\sum_{l = 1}^M\overleftrightarrow{B}_{i, l}\overleftrightarrow{H}_{k, l}\right)\right]\left(y_j - h_j\right).
\end{align}
\end{center}
}}
\end{center}

\section{Inclusion of moisture}
\label{sec:inclusion_of_moisture}

So far, moisture is taken into account in a separate assimilation process for efficiency.

\chapter{3D-Var}
\label{chap:3d-var}

\section{Technicalities}
\label{sec:technicalities_3d-var}

The observations used come from a time window $\left[-\frac{T}{2}, \frac{T}{2}\right]$ around the analysis time and are all taken to be valid at the analysis time. $T = 3$ h is a typical value..

\chapter{4D-Var}
\label{chap:4d-var}
%

\section{Technicalities}
\label{sec:technicalities_4d-var}

The observations used come from a time window $\left[-\frac{T}{2}, \frac{T}{2}\right]$ around the analysis time and are taken to be valid at individual time steps $n\Delta t$. $T = 6$ h and $\Delta t = 15$ min are typical values.

\appendix

\printbibliography

\end{document}


\section{Introduction}

Theoretical stellar model has been developed for decades to simulate star structure and evolution. However, star modelling is mostly based on sparse stellar grids \citep[e.g.][]{2016ApJ...823..102C} because model computations are time-consuming. Moreover, stellar model contents adjusted input parameters (e.g. the mixing-length parameter). Varying one of these adjusted parameter adds on an input demission and hence exponentially increases the computational cost. A comprehensive and fine stellar model grid is hence expensive.

A sparse grid is not ideal for the statistics analysis. Classical method like interpolation has been applied overcome this disadvantage. For instance, \citet{2016ApJS..222....8D} developed a method to transform stellar evolution tracks onto a uniform basis and then interpolate to construct stellar isochrones. More recently, \citet{2019MNRAS.484..771R} uses Bayesian statistics and a Markov Chain Monte Carlo approach to find a representative set of interpolated models from a grid. The interpolation of both works achieve good accuracy for 3-demission girds (inputs are mass, age, and metallicity). However, this approach becomes less reliable in higher demissions and it hence limits the flexibility for varying input physics. The algorithm is another approach that has been used in stellar codes \citep[e.g.][]{2013ApJS..208....4P}. It offers an automated likelihood minimisation to search for optimal solutions. This method is statistically sound and works fairly well for modelling individual stars. However, it becomes much less efficient while modelling a large sample, because the algorithm needs to iteratively compute stellar tracks many time for each single star.

Machine learning is being applied to the field of stellar research in many ways to efficiently characterise stars.
\citet{2016MNRAS.461.4206V} applied artificial neural networks \citep{bain1873mind,james1890principles}, i.e., a series of algorithms that endeavours to recognise underlying relationships in a set of data, and successfully determined the evolutionary parameters of the sun and sun-like stars based on spectroscopic and seismic measurements. Based on a similar artificial neural network interference, \citet{2019PASP..131j8001H} developed a method to achieve optimal initiation of CPU-intensive computations in a 6-dimensional parameter space. The method provides the optimal starting point for further and more detailed forward asteroseismic modelling for the core-hydrogen-burning stage of intermediate-mass and high-mass stars. Another example is that \citet{2021arXiv210313394M} trained neural networks to predict theoretical pulsation periods of high-order gravity modes, as well as the luminosity, effective temperature, and surface gravity for a given mass, age, overshooting parameter, diffusive envelope mixing, metallicity, and near-core rotation frequency. They compared neural-network predictions with observations to constrain a sample of 37 $\gamma$ Doradus stars.
%
Using different machine learning tools, \citet{2016ApJ...830...31B} trained a random forest regressors\citep{ho1995random}, which is an ensemble learning method for regression and operates by constructing a multitude of decision trees, to  rapidly estimating fundamental parameters of main-sequence solar-like stars from classical and asteroseismic observations. \citet{2018MNRAS.476.3233H} developed a convolutional neural network classifier that analyses visual features in asteroseismic frequency spectra to distinguish between red giant branch stars and helium-core burning stars. \citet{2019MNRAS.484.5315W} determined masses and ages for massive RGB stars from their spectra with a machine-learning method based on kernel principal component analysis, which is a nonlinear form of principal component analysis using integral operator kernel functions and can efficiently compute principal components in high dimensional feature spaces related to input space by some nonlinear map \citep{scholkopf1997kernel}. \citet{2020MNRAS.499.2445H} applied the mixture density network \citep{bishop1994mixture}, which learns a transformation from a set of input variables to a set of output variable, to determine stars' fundamental parameters like mass and age based on observed mode frequencies, spectroscopic and global seismic parameters.
%
It can be noted that the discriminative machine learning model is mostly used in above studies. The discriminative model treats observables as given facts to directly infer star properties. The method is efficient and easy for computation, however, the downside is not allowing any priors for the star properties in the Bayesian framework.
%
The generative model treats the data set in an opposite direction, says that, using the star fundamental parameters as given facts to predict observables. Predicted observables are then compared with observations to give posterior distributions for fundamental parameters. This approach offers flexibility to prior fundamental parameters. For instance, \citet{2021MNRAS.tmp.1343L} determined the initial helium fraction and the mixing-length parameters for a sample of Kepler dwarfs and subgiants based on the artificial neural network. The application of the generative model allow them giving either weakly or strongly informative priors whlie constraining the two fundamental parameters.

Because constructing a dense model grid is computationally expensive, we aim to apply the machine learning tool to transform a sparse model grid onto a continuous function, says that, to augment a model grid. We use a different machine learning algorithm that involves a Gaussian process (GP) to map between the stellar fundamental parameters and the observables. The Gaussian process measures the similarity between data points (i.e., the kernel function) to predict values for unseen points from training data. Because the generative model is advanced in terms of the priority, and we treat fundamental parameters as given facts.

We organise the rest of the paper as follow. Section \ref{sec:grid} contents descriptions about the computation of a representative stellar model grid. We then introduce the underline theory of GP and set up the training for GP in Section \ref{sec:gpmodel}. Section \ref{sec:results} demonstrates the results of GP predictions and we analyse the systematic uncertainties. We subsequently augment the stellar grid,  present a set of continuously-sampled models, and model 100 fake stars with these GP-trained models for testing the accuracy of our method in Section \ref{sec:augmentation}.
Finally we discuss advantages and limitations of this approach, highlight areas where improvements can be found in the near future, and summary conclusions in Section \ref{sec:conclusion}.

% Set the context of the work.
% Cite relevant earlier studies

%% Lots of work on estimating stellar properties where observables are compared with stellar models.  Typical approach is grid based.  Lots of citations.

%% Observables can come from all over.  Spectroscopic surveys (APOGEE, Galah, LAMOST, Gaia ESO, +), Astrometric Gaia, Photometric variability CoRoT, Kepler, K2, TESS, soon PLATO.

%% Lots of different models available with lots of different flavours - ask Tanda ...

%% Typical parameters to vary can refer to the star (mass, age, [Fe/H], Y_i) or they can refer to the model (MLT, overshoot, diffusion).  Most studies, certainly for field stars, treat all parameters as being independent.

% Describe the problem we aim to solve

%% Plenty of work exists on HBM models in astro (cite fest).  By pooling together parameters we can win - for example EB's/cluster age, chemical comp.  But also we could pool parameters of the models MLT, Ov.  If we take a Bayesian approach the pooled constraint on MLT or Ov has the ability to constrain stellar parameters (e.g., age, mass).  The posterior distribution is a joint distribution!

%% Curent limitation is that this is all very tricky computationally.  Great news though - breakthroughs in machine learning, sampling methods, and GPU implementation means we now have a shot at doing this.  In this paper we give a deminstration of principle for one way of proceeding.

% Layout of this paper ...

%%