\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}