c27685968a
I've gone ahead an uploaded a pdf version to the site.dev_compiler repository that matches the version in this CL. BUG= R=vsm@google.com Review URL: https://codereview.chromium.org/1253143002.
348 lines
12 KiB
TeX
348 lines
12 KiB
TeX
\documentclass[fleqn, draft]{article}
|
|
\usepackage{proof, amsmath, amssymb, ifthen}
|
|
\input{macros.tex}
|
|
|
|
% types
|
|
\newcommand{\Arrow}[3][-]{#2 \overset{#1}{\rightarrow} #3}
|
|
\newcommand{\Bool}{\mathbf{bool}}
|
|
\newcommand{\Bottom}{\mathbf{bottom}}
|
|
\newcommand{\Dynamic}{\mathbf{dynamic}}
|
|
\newcommand{\Null}{\mathbf{Null}}
|
|
\newcommand{\Num}{\mathbf{num}}
|
|
\newcommand{\Object}{\mathbf{Object}}
|
|
\newcommand{\TApp}[2]{#1\mathrm{<}#2\mathrm{>}}
|
|
\newcommand{\Type}{\mathbf{Type}}
|
|
\newcommand{\Weak}[1]{\mathbf{\{#1\}}}
|
|
\newcommand{\Sig}{\mathit{Sig}}
|
|
\newcommand{\Boxed}[1]{\langle #1 \rangle}
|
|
|
|
% expressions
|
|
\newcommand{\eassign}[2]{#1 = #2}
|
|
\newcommand{\eas}[2]{#1\ \mathbf{as}\ #2}
|
|
\newcommand{\ebox}[2]{\langle#1\rangle_{#2}}
|
|
\newcommand{\ecall}[2]{#1(#2)}
|
|
\newcommand{\echeck}[2]{\kwop{check}(#1, #2)}
|
|
\newcommand{\edcall}[2]{\kwop{dcall}(#1, #2)}
|
|
\newcommand{\edload}[2]{\kwop{dload}(#1, #2)}
|
|
\newcommand{\edo}[1]{\kwdo\{\,#1\,\}}
|
|
\newcommand{\eff}{\mathrm{ff}}
|
|
\newcommand{\eis}[2]{#1\ \mathbf{is}\ #2}
|
|
\newcommand{\elabel}[1][l]{\mathit{l}}
|
|
\newcommand{\elambda}[3]{(#1):#2 \Rightarrow #3}
|
|
\newcommand{\eload}[2]{#1.#2}
|
|
\newcommand{\enew}[3]{\mathbf{new}\,\TApp{#1}{#2}(#3)}
|
|
\newcommand{\enull}{\mathbf{null}}
|
|
\newcommand{\eobject}[2]{\kwobject_{#1} \{#2\}}
|
|
\newcommand{\eprimapp}[2]{\ecall{#1}{#2}}
|
|
\newcommand{\eprim}{\kwop{op}}
|
|
\newcommand{\esend}[3]{\ecall{\eload{#1}{#2}}{#3}}
|
|
\newcommand{\eset}[3]{\eassign{#1.#2}{#3}}
|
|
\newcommand{\esuper}{\mathbf{super}}
|
|
\newcommand{\ethis}{\mathbf{this}}
|
|
\newcommand{\ethrow}{\mathbf{throw}}
|
|
\newcommand{\ett}{\mathrm{tt}}
|
|
\newcommand{\eunbox}[1]{{*#1}}
|
|
|
|
% keywords
|
|
\newcommand{\kwclass}{\kw{class}}
|
|
\newcommand{\kwdo}{\kw{do}}
|
|
\newcommand{\kwelse}{\kw{else}}
|
|
\newcommand{\kwextends}{\kw{extends}}
|
|
\newcommand{\kwfun}{\kw{fun}}
|
|
\newcommand{\kwif}{\kw{if}}
|
|
\newcommand{\kwin}{\kw{in}}
|
|
\newcommand{\kwlet}{\kw{let}}
|
|
\newcommand{\kwobject}{\kw{object}}
|
|
\newcommand{\kwreturn}{\kw{return}}
|
|
\newcommand{\kwthen}{\kw{then}}
|
|
\newcommand{\kwvar}{\kw{var}}
|
|
|
|
% declarations
|
|
\newcommand{\dclass}[3]{\kwclass\ #1\ \kwextends\ #2\ \{#3\}}
|
|
\newcommand{\dfun}[4]{#2(#3):#1 = #4}
|
|
\newcommand{\dvar}[2]{\kwvar\ #1\ =\ #2}
|
|
|
|
|
|
\newcommand{\fieldDecl}[2]{\kwvar\ #1 : #2}
|
|
\newcommand{\methodDecl}[3]{\kwfun\ #1 : \iftrans{#2 \triangleleft} #3}
|
|
|
|
% statements
|
|
\newcommand{\sifthenelse}[3]{\kwif\ (#1)\ \kwthen\ #2\ \kwelse\ #3}
|
|
\newcommand{\sreturn}[1]{\kwreturn\ #1}
|
|
|
|
% programs
|
|
\newcommand{\program}[2]{\kwlet\ #1\ \kwin\ #2}
|
|
|
|
% relational operators
|
|
\newcommand{\sub}{\mathbin{<:}}
|
|
|
|
% utilities
|
|
\newcommand{\many}[1]{\overrightarrow{#1}}
|
|
\newcommand{\alt}{\ \mathop{|}\ }
|
|
\newcommand{\opt}[1]{[#1]}
|
|
\newcommand{\bind}[3]{#1 \Leftarrow\, #2\ \kw{in}\ #3}
|
|
|
|
\newcommand{\note}[1]{\textbf{NOTE:} \textit{#1}}
|
|
|
|
%dynamic semantics
|
|
\newcommand{\TypeError}{\mathbf{Error}}
|
|
|
|
% inference rules
|
|
\newcommand{\infrulem}[3][]{
|
|
\begin{array}{c@{\ }c}
|
|
\begin{array}{cccc}
|
|
#2 \vspace{-2mm}
|
|
\end{array} \\
|
|
\hrulefill & #1 \\
|
|
\begin{array}{l}
|
|
#3
|
|
\end{array}
|
|
\end{array}
|
|
}
|
|
|
|
\newcommand{\axiomm}[2][]{
|
|
\begin{array}{cc}
|
|
\hrulefill & #1 \\
|
|
\begin{array}{c}
|
|
#2
|
|
\end{array}
|
|
\end{array}
|
|
}
|
|
|
|
\newcommand{\infrule}[3][]{
|
|
\[
|
|
\infrulem[#1]{#2}{#3}
|
|
\]
|
|
}
|
|
|
|
\newcommand{\axiom}[2][]{
|
|
\[
|
|
\axiomm[#1]{#2}
|
|
\]
|
|
}
|
|
|
|
% judgements and relations
|
|
\newboolean{show_translation}
|
|
\setboolean{show_translation}{false}
|
|
\newcommand{\iftrans}[1]{\ifthenelse{\boolean{show_translation}}{#1}{}}
|
|
\newcommand{\ifnottrans}[1]{\ifthenelse{\boolean{show_translation}}{#1}}
|
|
|
|
\newcommand{\blockOk}[4]{#1 \vdash #2 \col #3\iftrans{\, \Uparrow\, #4}}
|
|
\newcommand{\declOk}[5][]{#2 \vdash_{#1} #3 \, \Uparrow\, \iftrans{#4\, :\,} #5}
|
|
\newcommand{\extends}[4][:]{#2[#3\ #1\ #4]}
|
|
\newcommand{\fieldLookup}[4]{#1 \vdash #2.#3\, \leadsto_f\, #4}
|
|
\newcommand{\methodLookup}[5]{#1 \vdash #2.#3\, \leadsto_m\, \iftrans{#4 \triangleleft} #5}
|
|
\newcommand{\fieldAbsent}[3]{#1 \vdash #3 \notin #2}
|
|
\newcommand{\methodAbsent}[3]{#1 \vdash #3 \notin #2}
|
|
\newcommand{\hastype}[3]{#1 \vdash #2 \, : \, #3}
|
|
\newcommand{\stmtOk}[5]{#1 \vdash #2 \, : \, #3\, \Uparrow \iftrans{#4\, :\,} #5}
|
|
\newcommand{\subst}[2]{[#1/#2]}
|
|
\newcommand{\subtypeOfOpt}[5][?]{#2 \vdash\ #3 \sub^{#1} #4\, \Uparrow\, #5}
|
|
\newcommand{\subtypeOf}[4][]{#2 \vdash\ #3 \sub^{#1} #4}
|
|
\newcommand{\yieldsOk}[5]{#1 \vdash #2 \, : \, #3\, \Uparrow\, \iftrans{#4\, :\,} #5}
|
|
\newcommand{\programOk}[3]{#1 \vdash #2\iftrans{\, \Uparrow\, #3}}
|
|
\newcommand{\ok}[2]{#1 \vdash #2\, \mbox{\textbf{ok}}}
|
|
\newcommand{\overrideOk}[4]{#1 \vdash #2\,\kwextends\, #3 \Leftarrow\, #4}
|
|
|
|
\newcommand{\down}[1]{\ensuremath{\downharpoonleft\!\!#1\!\!\downharpoonright}}
|
|
\newcommand{\up}[1]{\ensuremath{\upharpoonleft\!\!#1\!\!\upharpoonright}}
|
|
\newcommand{\sigof}[1]{\mathit{sigof}(#1)}
|
|
\newcommand{\typeof}[1]{\mathit{typeof}(#1)}
|
|
\newcommand{\sstext}[2]{\ifthenelse{\boolean{show_translation}}{#2}{#1}}
|
|
|
|
\newcommand{\evaluatesTo}[5][]{\{#2\alt #3\} \stepsto_{#1} \{#4 \alt #5\}}
|
|
|
|
|
|
\title{Dart strong mode definition}
|
|
|
|
\begin{document}
|
|
|
|
\textbf{\large PRELIMINARY DRAFT}
|
|
|
|
\section*{Syntax}
|
|
|
|
|
|
Terms and types. Note that we allow types to be optional in certain positions
|
|
(currently function arguments and return types, and on variable declarations).
|
|
Implicitly these are either inferred or filled in with dynamic.
|
|
|
|
There are explicit terms for dynamic calls and loads, and for dynamic type
|
|
checks.
|
|
|
|
Fields can only be read or set within a method via a reference to this, so no
|
|
dynamic set operation is required (essentially dynamic set becomes a dynamic
|
|
call to a setter). This just simplifies the presentation a bit. Methods may be
|
|
externally loaded from the object (either to call them, or to pass them as
|
|
closurized functions).
|
|
|
|
\[
|
|
\begin{array}{lcl}
|
|
\text{Type identifiers} & ::= & C, G, T, S, \ldots \\
|
|
%
|
|
\text{Arrow kind ($k$)} & ::= & +, -\\
|
|
%
|
|
\text{Types $\tau, \sigma$} & ::= &
|
|
T \alt \Dynamic \alt \Object \alt \Null \alt \Type \alt \Num \\ &&
|
|
\alt \Bool
|
|
\alt \Arrow[k]{\many{\tau}}{\sigma} \alt \TApp{C}{\many{\tau}} \\
|
|
%
|
|
\text{Ground types $\tau, \sigma$} & ::= &
|
|
\Dynamic \alt \Object \alt \Null \alt \Type \alt \Num \\ &&
|
|
\alt \Bool
|
|
\alt \Arrow[+]{\many{\Dynamic}}{\Dynamic} \alt \TApp{C}{\many{\Dynamic}} \\
|
|
%
|
|
\text{Optional type ($[\tau]$)} & ::= & \_ \alt \tau \\
|
|
%
|
|
\text{Term identifiers} & ::= & a, b, x, y, m, n, \ldots \\
|
|
%
|
|
\text{Primops ($\phi$)} & ::= & \mathrm{+}, \mathrm{-} \ldots \mathrm{||} \ldots \\
|
|
%
|
|
\text{Expressions $e$} & ::= &
|
|
x \alt i \alt \ett \alt \eff \alt \enull \alt \ethis \\&&
|
|
\alt \elambda{\many{x:\opt{\tau}}}{\opt{\sigma}}{s}
|
|
\alt \enew{C}{\many{\tau}}{} \\&&
|
|
\alt \eprimapp{\eprim}{\many{e}} \alt \ecall{e}{\many{e}} \\&&
|
|
\alt \eload{e}{m} \alt \eload{\ethis}{x} \\&&
|
|
\alt \eassign{x}{e} \alt \eset{\ethis}{x}{e} \\&&
|
|
\alt \ethrow \alt \eas{e}{\tau} \alt \eis{e}{\tau} \\
|
|
%
|
|
\text{Declaration ($\mathit{vd}$)} & ::= &
|
|
\dvar{x:\opt{\tau}}{e} \alt \dfun{\tau}{f}{\many{x:\tau}}{s} \\
|
|
%
|
|
\text{Statements ($s$)} & ::= & \mathit{vd} \alt e \alt \sifthenelse{e}{s_1}{s_2}
|
|
\alt \sreturn{e} \alt s;s \\
|
|
%
|
|
\text{Class decl ($\mathit{cd}$)} & ::= & \dclass{\TApp{C}{\many{T}}}{\TApp{G}{\many{\tau}}}{\many{\mathit{vd}}} \\
|
|
%
|
|
\text{Toplevel decl ($\mathit{td}$)} & ::= & \mathit{vd} \alt \mathit{cd}\\
|
|
%
|
|
\text{Program ($P$)} & ::= & \program{\many{\mathit{td}}}{s}
|
|
\end{array}
|
|
\]
|
|
|
|
|
|
Type contexts map type variables to their bounds.
|
|
|
|
Class signatures describe the methods and fields in an object, along with the
|
|
super class of the class. There are no static methods or fields.
|
|
|
|
The class hierararchy records the classes with their signatures.
|
|
|
|
The term context maps term variables to their types. I also abuse notation and
|
|
allow for the attachment of an optional type to term contexts as follows:
|
|
$\Gamma_\sigma$ refers to a term context within the body of a method whose class
|
|
type is $\sigma$.
|
|
|
|
\[
|
|
\begin{array}{lcl}
|
|
\text{Type context ($\Delta$)} & ::= & \epsilon \alt \Delta, T \sub \tau \\
|
|
\text{Class element ($\mathit{ce}$)} & ::= &
|
|
\fieldDecl{x}{\tau} \alt \methodDecl{f}{\tau}{\sigma} \\
|
|
\text{Class signature ($\Sig$)} & ::= &
|
|
\dclass{\TApp{C}{\many{T}}}{\TApp{G}{\many{\tau}}}{\many{\mathit{ce}}} \\
|
|
\text{Class hierarchy ($\Phi$)} & ::= & \epsilon \alt \Phi, C\ :\ \Sig \\
|
|
\text{Term context ($\Gamma$)} & ::= & \epsilon \alt \Gamma, x\ :\ \tau
|
|
\end{array}
|
|
\]
|
|
|
|
|
|
\section*{Subtyping}
|
|
|
|
\subsection*{Variant Subtyping}
|
|
|
|
We include a special kind of covariant function space to model certain dart
|
|
idioms. An arrow type decorated with a positive variance annotation ($+$)
|
|
treats $\Dynamic$ in its argument list covariantly: or equivalently, it treats
|
|
$\Dynamic$ as bottom. This variant subtyping relation captures this special
|
|
treatment of dynamic.
|
|
|
|
\axiom{\subtypeOf[+]{\Phi, \Delta}{\Dynamic}{\tau}}
|
|
|
|
\infrule{\subtypeOf{\Phi, \Delta}{\sigma}{\tau} \quad \sigma \neq \Dynamic}
|
|
{\subtypeOf[+]{\Phi, \Delta}{\sigma}{\tau}}
|
|
|
|
\infrule{\subtypeOf{\Phi, \Delta}{\sigma}{\tau}}
|
|
{\subtypeOf[-]{\Phi, \Delta}{\sigma}{\tau}}
|
|
|
|
\subsection*{Invariant Subtyping}
|
|
|
|
Regular subtyping is defined in a fairly standard way, except that generics are
|
|
uniformly covariant, and that function argument types fall into the variant
|
|
subtyping relation defined above.
|
|
|
|
\axiom{\subtypeOf{\Phi, \Delta}{\tau}{\Dynamic}}
|
|
|
|
\axiom{\subtypeOf{\Phi, \Delta}{\tau}{\Object}}
|
|
|
|
\axiom{\subtypeOf{\Phi, \Delta}{\Bottom}{\tau}}
|
|
|
|
\axiom{\subtypeOf{\Phi, \Delta}{\tau}{\tau}}
|
|
|
|
\infrule{(S\, :\, \sigma) \in \Delta \quad
|
|
\subtypeOf{\Phi, \Delta}{\sigma}{\tau}}
|
|
{\subtypeOf{\Phi, \Delta}{S}{\tau}}
|
|
|
|
\infrule{\subtypeOf[k_1]{\Phi, \Delta}{\sigma_i}{\tau_i} \quad i \in 0, \ldots, n \quad\quad
|
|
\subtypeOf{\Phi, \Delta}{\tau_r}{\sigma_r} \\
|
|
\quad (k_0 = \mbox{-}) \lor (k_1 = \mbox{+})
|
|
}
|
|
{\subtypeOf{\Phi, \Delta}
|
|
{\Arrow[k_0]{\tau_0, \ldots, \tau_n}{\tau_r}}
|
|
{\Arrow[k_1]{\sigma_0, \ldots, \sigma_n}{\sigma_r}}}
|
|
|
|
\infrule{\subtypeOf{\Phi, \Delta}{\tau_i}{\sigma_i} & i \in 0, \ldots, n}
|
|
{\subtypeOf{\Phi, \Delta}
|
|
{\TApp{C}{\tau_0, \ldots, \tau_n}}
|
|
{\TApp{C}{\sigma_0, \ldots, \sigma_n}}}
|
|
|
|
\infrule{(C : \dclass{\TApp{C}{T_0,\ldots,T_n}}{\TApp{C'}{\upsilon_0, \ldots, \upsilon_k}}{\ldots}) \in \Phi \\
|
|
\subtypeOf{\Phi, \Delta}{\subst{\tau_0, \ldots, \tau_n}{T_0, \ldots, T_n}{\TApp{C'}{\upsilon_0, \ldots, \upsilon_k}}}{\TApp{G}{\sigma_0, \ldots, \sigma_m}}}
|
|
{\subtypeOf{\Phi, \Delta}
|
|
{\TApp{C}{\tau_0, \ldots, \tau_n}}
|
|
{\TApp{G}{\sigma_0, \ldots, \sigma_m}}}
|
|
|
|
|
|
|
|
\section*{Typing}
|
|
\input{static-semantics}
|
|
|
|
\pagebreak
|
|
\section*{Elaboration}
|
|
\setboolean{show_translation}{true}
|
|
|
|
Elaboration is a type driven translation which maps a source Dart term to a
|
|
translated term which corresponds to the original term with additional dynamic
|
|
type checks inserted to reify the static unsoundness as runtime type errors.
|
|
For the translation, we extend the source language slightly as follows.
|
|
\[
|
|
\begin{array}{lcl}
|
|
\text{Expressions $e$} & ::= & \ldots
|
|
\alt \edcall{e}{\many{e}} \alt \edload{e}{m} \alt \echeck{e}{\tau}\\
|
|
\end{array}
|
|
\]
|
|
|
|
The expression language is extended with an explicitly checked dynamic call
|
|
operation, and explicitly checked dynamic method load operation, and a runtime
|
|
type test. Note that while a user level cast throws an exception on failure,
|
|
the runtime type test term introduced here produces a hard type error which
|
|
cannot be caught programmatically.
|
|
|
|
We also extend typing contexts slightly by adding an internal type to method signatures.
|
|
\[
|
|
\begin{array}{lcl}
|
|
\text{Class element ($\mathit{ce}$)} & ::= &
|
|
\fieldDecl{x}{\tau} \alt \methodDecl{f}{\tau}{\sigma} \\
|
|
\end{array}
|
|
\]
|
|
A method signature of the form $\methodDecl{f}{\tau}{\sigma}$ describes a method
|
|
whose public interface is described by $\sigma$, but which has an internal type
|
|
$\tau$ which is a subtype of $\sigma$, but which is properly covariant in any
|
|
type parameters. The elaboration introduces runtime type checks to mediate
|
|
between the two types. This is discussed further in the translation of classes
|
|
below.
|
|
|
|
\input{static-semantics}
|
|
|
|
|
|
\end{document}
|