@@ -11,7 +11,7 @@ of our type-checking implementation in Table~\ref{tab:implem} by

listing some examples none of which can be typed by current

systems (even though some system such as Flow and TypeScript

can type some of them by adding explicit type annotation, the code 6,

7, 9, and 10 and the \code{and\_} and \code{xor\_} functions at the end of this

7, 9, and 10 in Table~\ref{tab:implem} and, even more, the \code{and\_} and \code{xor\_} functions at the end of this

section are out of reach of current systems, even when using the right

explicit annotations). These examples and others can be tested in the

online toplevel available at

...

...

@@ -31,7 +31,7 @@ function under this assumption, but doing so collects that the type of

$\texttt{x}$ is specialized to \Int{} in the ``then'' case and to \Bool{}

in the ``else'' case. The function is thus type-checked twice more

under each hypothesis for \texttt{x}, yielding the precise type

$(\Int\to\Int)\land(\Bool\to\Bool)$. Note that w.r.t.\ rule \Rule{AbsInf+} of Section~\ref{sec:refining}, we improved the output of the computed

$(\Int\to\Int)\land(\Bool\to\Bool)$. Note that w.r.t.\ rule \Rule{AbsInf+} of Section~\ref{sec:refining}, our implementation improved the output of the computed

type. Indeed using rule~[{\sc AbsInf}+] we would obtain the

Whenever a function parameter is the argument of an

overloaded function, we record as possible types for this parameter

all the domains $t_i$ of the arrows that type the overloaded

function, restricted (via intersection) by the static type $t$ of the parameter and provided that the type is not empty ($t\wedge t_i\not\simeq\Empty$). In Code~9,

then \True, \Any, and $\lnot\True$ become candidate types for

\texttt{x} and this allows us to deduce the precise type given in the table. Finally, thanks to this rule it is no longer necessary to use a type case to force refinement. As a consequence we can define the functions \texttt{and\_} and \texttt{xor\_} more naturally as:

then the rule \Rule{OverApp} applies and \True, \Any, and $\lnot\True$ become candidate types for

\texttt{x}, which allows us to deduce the precise type given in the table. Finally, thanks to rule \Rule{OverApp} it is not necessary to use a type case to force refinement. As a consequence we can define the functions \texttt{and\_} and \texttt{xor\_} more naturally as:

\begin{alltt}\color{darkblue}\morecompact

let and_ = fun (x : Any) -> fun (y : Any) -> not_ (or_ (not_ x) (not_ y))

let xor_ = fun (x : Any) -> fun (y : Any) -> and_ (or_ x y) (not_ (and_ x y))

@@ -185,7 +185,29 @@ against the singleton types of all its inputs. But any finer partition

would return, in many cases, not a much better information, since most

partitions would collapse on the same return type: type-cases on the

parameter are the tipping points that are likely to make a difference, by returning different

types for different partitions thus yielding more precise typing. But they are not the only such tipping points: see rule \Rule{OverApp} in Section~\ref{sec:practical}.

types for different partitions thus yielding more precise typing.

Even though type cases in the body of a

function are tipping points that may change the type of the result

of the function, they are not the only ones: applications of overloaded functions play exactly the same role. We

therefore add to our deduction system a last further rule:\\[1mm]

\centerline{\(

\Infer[OverApp]

{

\Gamma\vdash e : \textstyle\bigvee\bigwedge_{i \in I}t_i\to{}s_i\\

Whenever a function parameter is the argument of an

overloaded function, we record as possible types for this parameter

all the domains $t_i$ of the arrows that type the overloaded

function, restricted (via intersection) by the static type $t$ of the parameter and provided that the type is not empty ($t\wedge t_i\not\simeq\Empty$). We show the full power of this rule on some practical examples in Section~\ref{sec:practical}.