From 78c57f245c798acc7ad3a6a3370119df89887abc Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 7 Jan 2022 17:08:57 +0100 Subject: [PATCH 01/15] Update section Variables --- specification/dartLangSpec.tex | 487 ++++++++++++++++++++++++--------- 1 file changed, 357 insertions(+), 130 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 331f6b81d9..ce78587363 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -1276,36 +1276,53 @@ \section{Variables} is equivalent to \code{\VAR{} x; \VAR{} y;} and -\code{\STATIC{} \FINAL{} String s1, s2 = "foo";} -is equivalent to -\code{\STATIC{} \FINAL{} String s1; \STATIC{} \FINAL{} String s2 = "foo";}.% +\code{\STATIC\,\,\LATE\,\,\FINAL{} String s1, s2 = "foo";} +is equivalent to having both +\code{\STATIC\,\,\LATE\,\,\FINAL{} String s1;} +and +\code{\STATIC\,\,\LATE\,\,\FINAL{} String s2 = "foo";}.% } \LMHash{}% It is possible for a variable declaration to include the modifier \COVARIANT. The effect of doing this with an instance variable is described elsewhere (\ref{instanceVariables}). -It is a compile-time error for the declaration of +It is a \Error{compile-time error} for the declaration of a variable which is not an instance variable to include the modifier \COVARIANT. \LMHash{}% In a variable declaration of one of the forms -\code{$N$ $v$;} -\code{$N$ $v$ = $e$;} +\code{$N$\,\,\id;} +or +\code{$N$\,\,\id{} = $e$;} where $N$ is derived from -\syntax{ }, -we say that $v$ is the \Index{declaring occurrence} of the identifier. +\syntax{ } and \id{} is an identifier, +we say that \id{} is the \Index{declaring occurrence} of the identifier. For every identifier which is not a declaring occurrence, we say that it is an \Index{referencing occurrence}. We also abbreviate that to say that an identifier is a \Index{declaring identifier} respectively an \Index{referencing identifier}. \commentary{% -In an expression of the form \code{$e$.\id} it is possible that -$e$ has static type \DYNAMIC{} and \id{} cannot be associated with -any specific declaration named \id{} at compile-time, -but in this situation \id{} is still a referencing identifier.% +In an expression of the form \code{$e$.$\id'$} it is possible that +$e$ has static type \DYNAMIC{} and $\id'$ cannot be associated with +any specific declaration named $\id'$ at compile-time, +but in this situation $\id'$ is still a referencing identifier.% +} + +\LMHash{}% +For brevity, we will refer to a variable using its name, +even though the name of a variable and the variable itself +are very different concepts. + +\commentary{% +So we will talk about ``the variable \id{}'', +rather than introducing ``the variable $v$ named \id{}''\!, +in order to be able to say ``the variable $v$'' later on. +This should not create any ambiguities, +\emph{because} the concept of a name and the concept of a variable +are so different.% } \LMHash{}% @@ -1317,100 +1334,184 @@ \section{Variables} A variable declared at the top-level of a library is referred to as either a \IndexCustom{library variable}{variable!library} or a \IndexCustom{top-level variable}{variable!top-level}. +It is a \Error{compile-time error} if a library variable declaration +has the modifier \STATIC. + +\LMHash{}% +A \IndexCustom{class variable}{variable!class} +is a variable whose declaration is +immediately nested inside a class declaration and +includes the modifier \STATIC. \LMHash{}% A \IndexCustom{static variable}{variable!static} is a variable that is not associated with a particular instance, but rather with an entire library or class. Static variables include library variables and class variables. -Class variables are variables whose declaration is -immediately nested inside a class declaration and -includes the modifier \STATIC. -A library variable is implicitly static. -It is a compile-time error to preface a top-level variable declaration -with the built-in identifier (\ref{identifierReference}) \STATIC. + +\LMHash{}% +A \Error{compile-time error} occurs if a static variable has a +no initializing expression and a type which is not nullable +(\ref{typeNullability}), +unless the variable declaration has +the modifier \LATE{} or \EXTERNAL. + +\LMHash{}% +A \IndexCustom{non-local variable}{variable!non-local} +is a library variable, a class variable, or an instance variable. +\commentary{% +That is, any kind of variable which is not a local variable.% +} \LMHash{}% A \IndexCustom{constant variable}{variable!constant} is a variable whose declaration includes the modifier \CONST. A constant variable must be initialized to a constant expression -(\ref{constants}) -or a compile-time error occurs. +(\ref{constants}), +or a \Error{compile-time error} occurs. \commentary{% An initializing expression of a constant variable occurs in a constant context (\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly.% +which means that \CONST{} modifiers need not be specified explicitly. +We need not specify that it is a compile-time error for a constant variable +to have the modifier \LATE, +because such declarations are not derivable syntactically.% } \LMHash{}% A \IndexCustom{final variable}{variable!final} is a variable whose binding is fixed upon initialization; -a final variable $v$ will always refer to the same object -after $v$ has been initialized. +a final variable \id{} will always refer to the same object +after \id{} has been initialized. A variable is final if{}f its declaration includes the modifier \FINAL{} or the modifier \CONST. - -\LMHash{}% A \IndexCustom{mutable variable}{variable!mutable} is a variable which is not final. -%% Note that the following relies on the assumption that inference has -%% already taken place, including member signature inference. For instance, -%% if `var x;` is an instance variable declaration that overrides `T get x;` -%% then we treat `var x;` as if it had been `T x;`. + +\subsection{Implicitly Induced Getters and Setters} +\LMLabel{implicitlyInducedGettersAndSetters} \LMHash{}% The following rules on implicitly induced getters and setters -apply to all static and instance variables. +apply to all non-local variable declarations. +\commentary{% +Local variable declarations +(\ref{localVariableDeclaration}) +do not induce getters or setters.% +} +For each form of declaration mentioned, +the modifier \STATIC{} may be present or absent. \LMHash{}% A variable declaration of one of the forms -\code{$T$ $v$;} -\code{$T$ $v$ = $e$;} -\code{\CONST{} $T$ $v$ = $e$;} -\code{\FINAL{} $T$ $v$;} -or \code{\FINAL{} $T$ $v$ = $e$;} -induces an implicit getter function (\ref{getters}) with signature -\code{$T$ \GET{} $v$} +\code{\LATE?\,\,$T$\,\,\id;} +\code{\LATE?\,\,$T$\,\,\id{} = $e$;} +\code{\CONST\,\,$T$\,\,\id{} = $e$;} +\code{\LATE?\,\,\FINAL\,\,$T$\,\,\id;} or +\code{\LATE?\,\,\FINAL\,\,$T$\,\,\id{} = $e$;} +where $T$ is a type +implicitly induces a getter (\ref{getters}) with header +\code{$T$\,\,\GET\,\,\id}, whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}). -In these cases the static type of $v$ is $T$. +In these cases the static type of \id{} is $T$. \LMHash{}% A variable declaration of one of the forms -\code{\VAR{} $v$;} -\code{\VAR{} $v$ = $e$;} -\code{\CONST{} $v$ = $e$;} -\code{\FINAL{} $v$;} -or \code{\FINAL{} $v$ = $e$;} -induces an implicit getter function with signature -\code{\DYNAMIC{} \GET{} $v$} +\code{\LATE?\,\,\VAR\,\,\id;} or +\code{\LATE?\,\,\FINAL\,\,\id;} +implicitly induces a getter with header +\code{\DYNAMIC\,\,\GET\,\,\id}, whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}). -%% TODO[inference]: We assume inference has taken place, i.e., inferred types -%% are written explicitly. Does this mean that the initialized variants -%% cannot exist (not even for `$e$` of type `dynamic`?). We probably don't -%% want to start talking about a grammar before inference and another one -%% after inference. -In these cases, the static type of $v$ is \DYNAMIC{} +In these cases, the static type of \id{} is \DYNAMIC{} (\ref{typeDynamic}). +\commentary{% +Type inference is assumed to have taken place already +(\ref{typeInference}). +For example, an instance variable declaration of the form +\code{\VAR\,\,x;} could have been transformed into +\code{$T$\,\,x;} based on member signatures named \code{x} in superinterfaces +of the enclosing class. +Hence, the type \DYNAMIC{} is only used as mentioned above when +type inference fails to provide a different type.% +} + +\LMHash{}% +A variable declaration of one of the forms +\code{\LATE?\,\,\VAR\,\,\id{} = $e$;} +\code{\CONST\,\,\id{} = $e$;} +or \code{\LATE?\,\,\FINAL\,\,\id{} = $e$;} +implicitly induces a getter with header +\code{$T$\,\,\GET\,\,\id} +where $T$ is the static type of $e$. +The semantics of an invocation of such getters is described below +(\ref{evaluationOfImplicitVariableGetters}). +In these cases, the static type of \id{} is $T$. + \LMHash{}% A mutable variable declaration of the form -\code{{} $T$ $v$;} -or \code{$T$ $v$ = $e$;} -induces an implicit setter function (\ref{setters}) with signature -\code{\VOID{} \SET{} $v$=($T$ $x$)} -whose execution sets the value of $v$ to the incoming argument $x$. +\code{\LATE?\,\,$T$\,\,\id;} or +\code{\LATE?\,\,$T$\,\,\id{} = $e$;} +implicitly induces a setter (\ref{setters}) with header +\code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. + +\LMHash{}% +A variable declaration of the form +\code{\LATE\,\,\FINAL\,\,$T$\,\,\id;} +implicitly induces a setter (\ref{setters}) with header +\code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)}. +If this setter is executed +in a situation where the variable \id{} has not been bound, +it will bind \id{} to the object that $x$ is bound to. +If this setter is executed +in a situation where the variable \id{} has been bound to an object, +a dynamic error occurs. + +\commentary{% +A late final variable declaration with no initializer is permitted. +It introduces a variable which may be assigned to +so long as the variable is not known to be definitely assigned. +The property that the variable is never mutated after initialization +is enforced dynamically rather than statically.% +} \LMHash{}% A mutable variable declaration of the form -\code{\VAR{} $v$;} -or \code{\VAR{} $v$ = $e$;} -induces an implicit setter function with signature -\code{\VOID{} \SET{} $v$=(\DYNAMIC{} $x$)} -whose execution sets the value of $v$ to the incoming argument $x$. +\code{\LATE?\,\,\VAR\,\,\id;} +implicitly induces a setter with header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. + +\commentary{% +It is again assumed that type inference has taken place already, +which could change \code{\VAR\,\,x;} to \code{$T$\,\,x;} +and hence take us to an earlier case.% +} + +\LMHash{}% +A mutable variable declaration of the form +\code{\LATE?\,\,\VAR\,\,\id{} = $e$;} +implicitly induces a setter with header +\code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)} +where $T$ is the static type of $e$, +whose execution sets the value of \id{} to the incoming argument $x$. + +\LMHash{}% +A variable declaration of the form +\code{\LATE\,\,\FINAL\,\,\id;} +implicitly induces a setter with header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}. +An execution of said setter +in a situation where the variable \id{} has not been bound +will bind \id{} to the object that the argument $x$ is bound to. +An execution of the setter +in a situation where the variable \id{} has been bound to an object +will incur a dynamic error. \LMHash{}% The scope into which the implicit getters and setters are introduced @@ -1418,26 +1519,28 @@ \section{Variables} \LMHash{}% A library variable introduces a getter into -the top level scope of the enclosing library. +the library scope of the enclosing library. A class variable introduces a static getter into -the immediately enclosing class. +the body scope of the immediately enclosing class. An instance variable introduces an instance getter into -the immediately enclosing class. +the body scope of the immediately enclosing class. \LMHash{}% A mutable library variable introduces a setter into -the top level scope of the enclosing library. +the library scope of the enclosing library. A mutable class variable introduces a static setter into -the immediately enclosing class. -A mutable instance variable introduces an instance setter into -the immediately enclosing class. +the body scope of the immediately enclosing class. +An instance variable that introduces a setter +(\commentary{it can be non-final, or late and final}) +introduces an instance setter into +the body scope of the immediately enclosing class. \LMHash{}% -Let $v$ be variable declared in an initializing variable declaration, +Let \id{} be variable declared in an initializing variable declaration, and let $e$ be the associated initializing expression. -It is a compile-time error if the static type of $e$ -is not assignable to the declared type of $v$. -It is a compile-time error if a final instance variable +It is a \Error{compile-time error} if the static type of $e$ +is not assignable to the declared type of \id. +It is a \Error{compile-time error} if a final instance variable whose declaration has an initializer expression is also initialized by a constructor, either by an initializing formal or an initializer list entry. @@ -1446,34 +1549,39 @@ \section{Variables} It is a compile-time error if a final instance variable that has been initialized by means of an initializing formal of a constructor $k$ -is also initialized in the initializer list of $k$ (\ref{initializerLists}). +is also initialized in the initializer list of $k$ +(\ref{initializerLists}). -%% TODO(eernst): Not quite true, because of special lookup for assignment! -A static final variable $v$ does not induce a setter, -so unless a setter named \code{$v$=} is in scope -it is a compile-time error to assign to $v$. +A non-late static final variable \id{} does not induce a setter, +so unless a setter named \code{\id=} can be found by lexical lookup +(\ref{lexicalLookup}), +it is a compile-time error to assign to \id. -Similarly, assignment to a final instance variable $v$ +Similarly, assignment to a non-late final instance variable \id{} is a compile-time error, -unless a setter named \code{$v$=} is in scope, +unless a setter named \code{\id=} can be found by lexical lookup, or the receiver has type \DYNAMIC. -$v$ can be initialized in its declaration or in initializer lists, +\id{} can be initialized in its declaration or in initializer lists, but initialization and assignment is not the same thing. When the receiver has type \DYNAMIC{} such an assignment is not a compile-time error, -% This error can occur because the receiver is dynamic. -but if there is no setter it will cause a dynamic error.% +but if there is no such setter it will cause a dynamic error.% } \LMHash{}% -A variable that has no initializing expression has the null object +Consider a variable \id{} with no initializing expression +whose declaration does not have the modifier \LATE. +If this is not a compile-time error then \id{} has the null object (\ref{null}) as its initial value. + +\LMHash{}% Otherwise, variable initialization proceeds as follows: \LMHash{}% -Static variable declarations with an initializing expression -are initialized lazily +A static variable declaration +(\commentary{that is, a declaration of a library variable or a class variable}) +with an initializing expression is initialized lazily (\ref{evaluationOfImplicitVariableGetters}). \rationale{% @@ -1491,11 +1599,11 @@ \section{Variables} } \LMHash{}% -Initialization of an instance variable $v$ +Initialization of an instance variable \id{} with an initializing expression $e$ proceeds as follows: $e$ is evaluated to an object $o$ -and the variable $v$ is bound to $o$. +and the variable \id{} is bound to $o$. \commentary{% It is specified elsewhere when this initialization occurs, @@ -1514,10 +1622,9 @@ \section{Variables} } \LMHash{}% -% This error can occur due to implicit casts, and -% for instance variables also when a setter is called dynamically. +% This error can occur due to an implicit downcast from \DYNAMIC. It is a dynamic type error if the dynamic type of $o$ is not -a subtype of the actual type of the variable $v$ +a subtype of the actual type of the variable \id{} (\ref{actualTypes}). @@ -1525,54 +1632,174 @@ \subsection{Evaluation of Implicit Variable Getters} \LMLabel{evaluationOfImplicitVariableGetters} \LMHash{}% -\BlindDefineSymbol{d, v}% -Let $d$ be the declaration of a static or instance variable $v$. -If $d$ is an instance variable, -then the invocation of the implicit getter of $v$ evaluates to -the object stored in $v$. -If $d$ is a static variable -(\commentary{which can be a library variable}) -then the implicit getter method of $v$ executes as follows: +\BlindDefineSymbol{d, \id}% +Let $d$ be the declaration of a non-local variable named \id. +For brevity, we will refer to it below as +`the variable \id' or `the variable $d$', or just as `\id' or `$d$'. + +\LMHash{}% +\Case{Non-late instance variable} +If $d$ declares an instance variable which does not have the modifier \LATE, +then the invocation of the implicit getter of \id{} evaluates to +the object that \id{} is bound to. +\EndCase + +\LMHash{}% +\Case{Late, initialized instance variable} +If $d$ declares an instance variable which has the modifier \LATE{} +and an initializing expression $e$, +then an invocation of the implicit getter of \id{} +in a situation where the variable \id{} has not been bound +will evaluate $e$ to an object $o$, +bind \id{} to $o$, +and complete returning $o$; +if the evaluation of $e$ throws then +the invocation of the getter throws the same object and stack trace. +An invocation of the implicit getter of \id{} +in a situation where the variable \id{} has been bound to an object $o'$ +evaluates to $o'$. + +\commentary{% +Consider an instance variable declaration of the form +\code{\LATE\,\,\VAR\,\,x = $e$;}. +Perhaps surprisingly, +if the variable \code{x} has been bound to an object +when its getter is invoked for the first time, +$e$ will never be executed. +Another example worth noting +is given below in the text about +a non-constant static variable with an initializer. +That example (i.e., the one with \code{bool\,\,b;} and \code{int\,\,i = ...;}) +works in the same manner when \code{i} is an instance variable.% +} +\EndCase + +\LMHash{}% +\Case{Late, uninitialized instance variable} +Consider the case where $d$ declares an instance variable +which has the modifier \LATE{} and no initializing expression. +Assume that the object denoted by \THIS{} was created with +a constructor invocation where said instance variable was initialized +by an initializing formal or by an initializer list element, +or that the corresponding setter named \code{\id=} has been executed +and completed without throwing. +In this case, an invocation of the implicit getter of \id{} +will evaluate to the object that \id{} is bound to. +Otherwise +(\commentary{when this variable has never been bound}), +the getter invocation incurs a dynamic error. +\EndCase + +\LMHash{}% +\Case{Static variable} +If $d$ declares a static variable +(\commentary{that is, a library variable or a class variable}), +the implicitly induced getter of \id{} executes as follows: + \begin{itemize} -\item {\bf Non-constant variable declaration with initializer}. - If $d$ is of one of the forms - \code{\VAR{} $v$ = $e$;}, - \code{$T$ $v$ = $e$;}, - \code{\FINAL{} $v$ = $e$;}, - \code{\FINAL{} $T$ $v$ = $e$;}, - \code{\STATIC{} $v$ = $e$;}, - \code{\STATIC{} $T$ $v$ = $e$; }, - \code{\STATIC{} \FINAL{} $v$ = $e$; } or - \code{\STATIC{} \FINAL{} $T$ $v$ = $e$;} - and no object has yet been stored into $v$ - then the initializing expression $e$ is evaluated. - If, during the evaluation of $e$, the getter for $v$ is invoked, - a \code{CyclicInitializationError} is thrown. - If the evaluation of $e$ throws an exception $e$ and stack trace $s$, - the null object (\ref{null}) is stored into $v$; - the execution of the getter then throws $e$ and stack trace $s$. - Otherwise, the evaluation of $e$ succeeded yielding an object $o$; - then $o$ is stored into $v$ and - the execution of the getter completes by returning $o$. - Otherwise, - (\commentary{when an object $o$ has been stored in $v$}) - execution of the getter completes by returning $o$. -\item {\bf Constant variable declaration}. +\item \emph{Non-constant variable with an initializer.} + Consider the case where $d$ has one of the forms + \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;}, + \code{\STATIC?\,\,\LATE?\,\,\FINAL\,\,\id{} = $e$;}, or + \code{\STATIC?\,\,\LATE?\,\,\FINAL?\,\,$T$\,\,\id{} = $e$;}. + + The invocation of the implicitly induced getter of \id{} + in a situation where the variable \id{} has not been bound + will evaluate $e$ to an object $o$, bind \id{} to $o$, + and complete returning $o$; + if the evaluation of $e$ throws, + the invocation of the getter throws the same object and stack trace. + An invocation of the getter of \id{} + in a situation where the variable \id{} has been bound to an object $o'$ + completes returning $o'$. + + \commentary{% + Note that an initializing expression can have side effects + that are significant during initialization. + For example:% + } + +\begin{dartCode} +bool b = \TRUE; +int i = (() => (b = !b) ? (i = 10) : i + 1)(); +\\ +\VOID{} main() \{ + print(i); // '11'. +\} +\end{dartCode} + + \commentary{% + In this example, \code{main} invokes + the implicitly induced getter named \code{i}, + and the variable \code{i} has not been bound at this point. + Hence, evaluation of the initializing expression proceeds. + This causes \code{b} to be toggled to \FALSE, + which again causes \code{i + 1} to be evaluated. + This causes the getter \code{i} to be invoked again, + and it is still true that the variable has not been bound, + so the initializing expression is evaluated again. + This toggles \code{b} to \TRUE, + which causes \code{i = 10} to be evaluated, + which causes the implicitly induced setter named \code{i=} to be invoked, + and the most recent invocation of the getter \code{i} + returns 10. + This makes \code{i + 1} evaluate to 11, + and the variable is then bound to 11. + Finally, the invocation of the getter \code{i} in \code{main} + completes returning 11.% + } + + \commentary{% + Note that this is a change from the semantics older versions of Dart: + Throwing an exception during initializer evaluation no longer sets the + variable to \code{null}, + and reading the variable during initializer evaluation + no longer causes a dynamic error.% + } +\item \emph{Constant variable.} If $d$ is of one of the forms - \code{\CONST{} $v$ = $e$;}, - \code{\CONST{} $T$ $v$ = $e$;}, - \code{\STATIC{} \CONST{} $v$ = $e$;} or - \code{\STATIC{} \CONST{} $T$ $v$ = $e$;} - the result of the getter is the value of the constant expression $e$. + \code{\STATIC?\,\,\LATE?\,\,\CONST{} $v$ = $e$;} or + \code{\STATIC?\,\,\LATE?\,\,\CONST{} $T$ $v$ = $e$;}. + the result of the executing the implicitly induced getter is + the value of the constant expression $e$. \commentary{% Note that a constant expression cannot depend on itself, so no cyclic references can occur.% } -\item {\bf Variable declaration without initializer}. - The result of executing the getter method is the object stored in $v$. - \commentary{This may be the initial value, that is, the null object.} +\item \emph{Variable without an initializer.} + Consider the case where $d$ has one of the forms + \code{\STATIC?\,\,\VAR\,\,\id;} or + \code{\STATIC?\,\,$T$\,\,\id;}. + The result of executing the implicitly induced getter of \id{} is + the object that \id{} is bound to. + + \commentary{% + This may be the initial value, that is, the null object + (the typed variant is an error unless $T$ is nullable). + Note that forms like \code{\FINAL\,\,\id;} and + \code{\FINAL\,\,$T$\,\,\id;} are irrelevant here: + They are syntax errors at the top level, + and instance variables were specified earlier in this section. + The forms \code{\STATIC\,\,\FINAL\,\,\id;} and + \code{\STATIC\,\,\FINAL\,\,$T$\,\,\id;} + are syntax errors as well.% + } + + Consider the situation where $d$ has one of the forms + \code{\STATIC?\,\,\LATE\,\,\VAR\,\,\id;}, + \code{\STATIC?\,\,\LATE\,\,\FINAL\,\,\id;}, or + \code{\STATIC?\,\,\LATE\,\,\FINAL?\,\,$T$\,\,\id;}. + An execution of the implicitly induced getter of \id{} + in a situation where the variable \id{} is bound to an object $o$ + will complete returning $o$. + An execution of the implicitly induced getter of \id{} + in a situation where the variable \id{} is unbound + will incur a dynamic error. \end{itemize} +% Reduce whitespace after itemized list: This is just an end symbol. +\vspace{-\baselineskip}\EndCase + \section{Functions} \LMLabel{functions} From ff63e835979ad0e832ad9994c84539cbed56fc08 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 7 Jan 2022 17:09:55 +0100 Subject: [PATCH 02/15] Rebasing --- specification/dart.sty | 135 ++++++++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 21 deletions(-) diff --git a/specification/dart.sty b/specification/dart.sty index 7896caccd6..adabd48e87 100644 --- a/specification/dart.sty +++ b/specification/dart.sty @@ -68,6 +68,9 @@ \def\WITH{\keyword{with}} \def\YIELD{\keyword{yield}} +% Used for inline code snippets. +\newcommand{\code}[1]{\texttt{#1}} + % Used to specify syntactic sugar. \def\LET{\keyword{let}} \newcommand{\Let}[3]{\code{\LET\,\,{#1}\,=\,{#2}\ \IN\ {#3}}} @@ -78,8 +81,8 @@ \newcommand{\LetMany}[5]{% \code{\LET\,\,{#1}\,=\,{#2},\ $\cdots$,\ {#3}\,=\,{#4}\ \IN\ {#5}}} -% Used for inline code snippets. -\def\code#1{\texttt{#1}} +% Used for inline meta-code snippets +\newcommand{\metaCode}[1]{{\color{metaColor}\texttt{#1}}} % `call` has no special lexical status, so we just use \code{}. \def\CALL{\code{call}} @@ -112,6 +115,7 @@ \definecolor{normativeColor}{rgb}{0,0,0} \definecolor{commentaryColor}{rgb}{0.5,0.5,0.5} \definecolor{rationaleColor}{rgb}{0.5,0.5,0.5} +\definecolor{metaColor}{rgb}{0,0,1} % Environments for different kinds of text. \newenvironment{Q}[1]{{\bf{}Upcoming: {#1}}}{} @@ -132,7 +136,7 @@ \newcommand{\Case}[1]{\textbf{Case }$\langle\hspace{0.1em}${#1}$\hspace{0.1em}\rangle$\textbf{.}} \newcommand{\EndCase}{\mbox{}\hfill$\scriptscriptstyle\Box$\xspace} -\newenvironment{dartCode}[1][!ht] {% +\newenvironment{dartCode}[1][!ht]{% \def\@programcr{\@addfield\strut}% \let\\=\@programcr% \relax\@vobeyspaces\obeylines% @@ -140,7 +144,7 @@ \vspace{1em}% }{\normalcolor\vspace{1em}} -\newenvironment{normativeDartCode}[1][!ht] {% +\newenvironment{normativeDartCode}[1][!ht]{% \def\@programcr{\@addfield\strut}% \let\\=\@programcr% \relax\@vobeyspaces\obeylines% @@ -148,6 +152,14 @@ \vspace{1em}% }{\normalcolor\vspace{1em}} +\newenvironment{metaLevelCode}[1][!ht]{% + \def\@programcr{\@addfield\strut}% + \let\\=\@programcr% + \relax\@vobeyspaces\obeylines% + \ttfamily\color{metaColor}% + \vspace{1em}% +}{\normalcolor\vspace{1em}} + % Used for comments in a code context. \def\comment#1{\textsf{#1}} @@ -157,7 +169,7 @@ % Used for defining occurrence of phrase, with customized index entry. \newcommand{\IndexCustom}[2]{% - \leavevmode\marginpar{\ensuremath{\diamond}}\emph{#1}\index{#2}} + \leavevmode\marginpar{\ensuremath{_{^\vartriangle}}}\emph{#1}\index{#2}} % Used for the defining occurrence of a local symbol. \newcommand{\DefineSymbol}[1]{% @@ -178,7 +190,11 @@ % Same appearance, but not adding an entry to the index. \newcommand{\NoIndex}[1]{% - \leavevmode\marginpar{\quad\ensuremath{\diamond}}\emph{#1}} + \leavevmode\marginpar{\ensuremath{_{^\vartriangle}}}\emph{#1}} + +% Mark a compile-time error in the margin. +\newcommand{\Error}[1]{% + \leavevmode\marginpar{\ensuremath{_{^\ominus}}}{#1}} % Used to specify comma separated lists of similar symbols. \newcommand{\List}[3]{\ensuremath{{#1}_{#2},\,\ldots,\ {#1}_{#3}}} @@ -190,6 +206,22 @@ \newcommand{\PairList}[4]{\ensuremath{% {#1}_{#3}\ {#2}_{#3},\,\ldots,\ {#1}_{#4}\ {#2}_{#4}}} +% Used to specify named arguments. +% Parameters: Parameter name, argument name, index at start, index at end. +\newcommand{\NamedArgumentList}[4]{\PairList{#1}{\!\!:\,\,{#2}}{#3}{#4}} + +% Used to specify an argument list including positional and named arguments. +% Parameters: Argument name, number of positional arguments, named parameter +% name, number of named arguments. +\newcommand{\ArgumentList}[4]{% + \List{#1}{1}{#2},\ \NamedArgumentList{#3}{#1}{{#2}+1}{{#2}+{#4}}} + +% Used to specify a standard argument list. +\newcommand{\ArgumentListStd}{\ArgumentList{a}{n}{x}{k}} + +% Used to specify a standard type argument list. +\newcommand{\TypeArgumentListStd}{\List{A}{1}{r}} + % Used to specify a list of tuples of the form $(K_j, V_j)$ which are % used with collection literals. \newcommand{\KeyValueTypeList}[4]{\ensuremath{% @@ -279,26 +311,28 @@ % Used to specify function type parameter lists with named optionals. % Arguments: Parameter type, number of required parameters, -% name of optional parameters, number of optional parameters. -\newcommand{\FunctionTypeNamedArguments}[4]{% - \List{#1}{1}{#2},\ \{\PairList{#1}{#3}{{#2}+1}{{#2}+{#4}}\}} - +% name of optional parameters, number of optional parameters, +% name of `required` symbol. +\newcommand{\FunctionTypeNamedArguments}[5]{% + \List{#1}{1}{#2},\ \{\TripleList{#5}{#1}{#3}{{#2}+1}{{#2}+{#4}}\}} + \newcommand{\FunctionTypeNamedArgumentsStd}{% - \FunctionTypeNamedArguments{T}{n}{x}{k}} + \FunctionTypeNamedArguments{T}{n}{x}{k}{r}} % Used to specify function types with named parameters: % Arguments: Return type, spacer, type parameter name, bound name, % number of type parameters, parameter type, number of required parameters, -% name of optional parameters, number of optional parameters. +% name of optional parameters, number of optional parameters, +% name of `required` symbol. \newcommand{\FunctionTypeNamed}[9]{% - \FunctionType{#1}{#2}{#3}{#4}{#5}{% - \FunctionTypeNamedArguments{#6}{#7}{#8}{#9}}} + \FunctionType{#1}{#2}{#3}{#4}{#5}{\\ + \mbox{}\qquad\FunctionTypeNamedArguments{#6}{#7}{#8}{#9}{#10}}} % Same as \FunctionType except suitable for inline usage, hence omitting % the spacer argument. -\newcommand{\RawFunctionTypeNamed}[8]{% +\newcommand{\RawFunctionTypeNamed}[9]{% \RawFunctionType{#1}{#2}{#3}{#4}{% - \FunctionTypeNamedArguments{#5}{#6}{#7}{#8}}} + \FunctionTypeNamedArguments{#5}{#6}{#7}{#8}{#9}}} % Used to specify function types with no optional parameters: % Arguments: Return type, spacer, type parameter name, bound name, @@ -314,10 +348,10 @@ \RawFunctionTypePositional{#1}{X}{B}{s}{T}{n}{k}} \newcommand{\FunctionTypeNamedStd}[1]{% - \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}} + \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}{r}} \newcommand{\RawFunctionTypeNamedStd}[1]{% - \RawFunctionTypeNamed{#1}{X}{B}{s}{T}{n}{x}{k}} + \RawFunctionTypeNamed{#1}{X}{B}{s}{T}{n}{x}{k}{r}} \newcommand{\FunctionTypeAllRequiredStd}[1]{% \FunctionTypeAllRequired{#1}{ }{X}{B}{s}{T}{n}} @@ -326,7 +360,10 @@ \FunctionTypePositional{#1}{\\}{X}{B}{s}{T}{n}{k}} \newcommand{\FunctionTypeNamedStdCr}[1]{% - \FunctionTypeNamed{#1}{\\}{X}{B}{s}{T}{n}{x}{k}} + \FunctionTypeNamed{#1}{\\}{X}{B}{s}{T}{n}{x}{k}{r}} + +\newcommand{\FunctionTypeNamedStdArgCr}[1]{% + \FunctionTypeNamedArgCr{#1}{ }{X}{B}{s}{T}{n}{x}{k}{r}} \newcommand{\FunctionTypeAllRequiredStdCr}[1]{% \FunctionTypeAllRequired{#1}{\\}{X}{B}{s}{T}{n}} @@ -342,13 +379,13 @@ % Judgment expressing that a subtype relation exists. \newcommand{\Subtype}[3]{\ensuremath{{#1}\vdash{#2}\,<:\,{#3}}} -\newcommand{\SubtypeStd}[2]{\Subtype{\Gamma}{#1}{#2}} +\newcommand{\SubtypeStd}[2]{\Subtype{\Delta}{#1}{#2}} % Subtype judgment where the environment is omitted (NE: "no environment"). \newcommand{\SubtypeNE}[2]{\ensuremath{{#1}\,<:\,{#2}}} % Judgment expressing that a supertype relation exists. \newcommand{\Supertype}[3]{\ensuremath{{#1}\vdash{#2}\,:>\,{#3}}} -\newcommand{\SupertypeStd}[2]{\Supertype{\Gamma}{#1}{#2}} +\newcommand{\SupertypeStd}[2]{\Supertype{\Delta}{#1}{#2}} % Judgment expressing that an assignability relation exists. \newcommand{\AssignableRelationSymbol}{\ensuremath{\Longleftrightarrow}} @@ -394,6 +431,62 @@ \ensuremath{{#2}}% } +\newcommand{\FlattenName}{\metavar{flatten}} +\newcommand{\Flatten}[1]{\ensuremath{\FlattenName(\code{#1})}} + +\newcommand{\NominalTypeDepthName}{\metavar{nominalTypeDepth}} +\newcommand{\NominalTypeDepth}[1]{% + \ensuremath{\NominalTypeDepthName(\code{#1})}} + +\newcommand{\TopMergeTypeName}{\metavar{topMergeType}} +\newcommand{\TopMergeType}[2]{% + \ensuremath{\TopMergeTypeName(\code{{#1},\,\,{#2}})}} + +\newcommand{\NonNullTypeName}{\metavar{nonNullType}} +\newcommand{\NonNullType}[1]{\ensuremath{\NonNullTypeName(\code{#1})}} + +\newcommand{\IsTopTypeName}{\metavar{isTopType}} +\newcommand{\IsTopType}[1]{\ensuremath{\IsTopTypeName(\code{#1})}} + +\newcommand{\IsObjectTypeName}{\metavar{isObjectType}} +\newcommand{\IsObjectType}[1]{\ensuremath{\IsObjectTypeName(\code{#1})}} + +\newcommand{\IsBottomTypeName}{\metavar{isBottomType}} +\newcommand{\IsBottomType}[1]{\ensuremath{\IsBottomTypeName(\code{#1})}} + +\newcommand{\IsNullTypeName}{\metavar{isNullType}} +\newcommand{\IsNullType}[1]{\ensuremath{\IsNullTypeName(\code{#1})}} + +\newcommand{\IsMoreTopTypeName}{\metavar{isMoreTopType}} +\newcommand{\IsMoreTopType}[2]{% + \ensuremath{\IsMoreTopTypeName(\code{{#1},\,\,{#2}})}} + +\newcommand{\IsMoreBottomTypeName}{\metavar{isMoreBottomType}} +\newcommand{\IsMoreBottomType}[2]{% + \ensuremath{\IsMoreBottomTypeName(\code{{#1},\,\,{#2}})}} + +\newcommand{\NormalizedTypeOfName}{\metavar{normalizedType}} +\newcommand{\NormalizedTypeOf}[1]{% + \ensuremath{\NormalizedTypeOfName(\code{#1})}} + +\newcommand{\FutureValueTypeOfName}{\metavar{futureValueType}} +\newcommand{\FutureValueTypeOf}[1]{% + \ensuremath{\FutureValueTypeOfName(\code{#1})}} + +\newcommand{\UpperBoundTypeName}{\metavar{standardUpperBound}} +\newcommand{\UpperBoundType}[2]{% + \ensuremath{\UpperBoundTypeName(\code{{#1},\,\,{#2}})}} + +\newcommand{\LowerBoundTypeName}{\metavar{standardLowerBound}} +\newcommand{\LowerBoundType}[2]{% + \ensuremath{\LowerBoundTypeName(\code{{#1},\,\,{#2}})}} + +\newcommand{\DefEquals}[2]{\ensuremath{{#1}\stackrel{\vartriangle}{=}{#2}}} +\newcommand{\DefEqualsNewline}[2]{ + \ensuremath{{#1}\stackrel{\vartriangle}{=}}\\ + \ensuremath{{#2}}% +} + % ---------------------------------------------------------------------- % Support for hash valued Location Markers From 2c1e6cbb7a1c85a94f75b9c58afb17bfad456e33 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 7 Jan 2022 17:37:16 +0100 Subject: [PATCH 03/15] Update section Local Variable Declaration, update \Gamma to \Delta --- specification/dartLangSpec.tex | 204 ++++++++++++++++++++++++--------- 1 file changed, 148 insertions(+), 56 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index ce78587363..c12c062999 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -17582,6 +17582,7 @@ \subsection{Local Variable Declaration} apply to local variables with the same definitions as for other variables (\ref{variables}). +%% TODO(eernst): May need updates/deletion when flow analysis is integrated. \LMHash{}% We say that a local variable $v$ is \Index{potentially mutated} in some scope $s$ @@ -17590,41 +17591,108 @@ \subsection{Local Variable Declaration} \LMHash{}% A local variable declaration of the form \code{\VAR{} $v$;} is equivalent to \code{\VAR{} $v$ = \NULL;}. -A local variable declaration of the form \code{$T$ $v$;} is equivalent to -\code{$T$ $v$ = \NULL;}. - -\commentary{% -This holds regardless of the type $T$. -E.g., \code{int i;} is equivalent to \code{int i = null;}.% -} +If $T$ is a nullable type +(\ref{typeNullability}) +then a local variable declaration of the form \code{$T$ $v$;} +is equivalent to \code{$T$ $v$ = \NULL;}. + +%% TODO(eernst): Revise when flow analysis is added. +\commentary{% +If $T$ is a potentially non-nullable type +then a local variable declaration of the form \code{$T$ $v$;} is allowed, +but an expression that gives rise to evaluation of $v$ +is a compile-time error unless flow analysis +(\ref{flowAnalysis}) +shows that the variable is guaranteed to have been initialized.% +} + +\LMHash{}% +A local variable has an associated +\IndexCustom{declared type}{local variable!declared type} +which is determined from its declaration. +A local variable also has an associated +\IndexCustom{type}{local variable!type} +which is determined by flow analysis +(\ref{flowAnalysis}) +via a process known as type promotion +(\ref{typePromotion}). \LMHash{}% -The type of a local variable with a declaration of one of the forms -\code{$T$ $v$ = $e$;} -\code{\CONST{} $T$ $v$ = $e$;} -\code{\FINAL{} $T$ $v$ = $e$;} +The declared type of a local variable with a declaration of one of the forms +\code{\LATE?\,\,$T$\,\,$v$ = $e$;} +\code{\LATE?\,\,\FINAL\,\,$T$\,\,$v$ = $e$;} +\code{\CONST\,\,$T$\,\,$v$ = $e$;} is $T$. -The type of a local variable with a declaration of one of the forms -\code{\VAR{} $v$ = $e$;} -\code{\CONST{} $v$ = $e$;} -\code{\FINAL{} $v$ = $e$;} -is \DYNAMIC. + +\LMHash{}% +The declared type of a local variable with a declaration of one of the forms +\code{\LATE?\,\,\VAR\,\,$v$ = $e$;} +\code{\LATE?\,\,\FINAL\,\,$v$ = $e$;} +\code{\CONST\,\,$v$ = $e$;} +is determined as follows: + +\begin{itemize} +\item + If the static type of $e$ is \code{Null} then + the declared type of $v$ is \DYNAMIC. +\item + If the static type of $e$ is of the form \code{$X$\,\&\,$T$} + where $X$ is a type variable + (\ref{intersectionTypes}), + the declared type of $v$ is \code{X}. + \commentary{% + In this case $v$ is immediately promoted + (\ref{typePromotion}).% + } +\item + Otherwise, the declared type of $v$ is the static type of $e$. +\end{itemize} \LMHash{}% Let $v$ be a local variable declared by an initializing variable declaration, and let $e$ be the associated initializing expression. -It is a compile-time error if the static type of $e$ is not assignable to -the type of $v$. -It is a compile-time error if a local variable $v$ is final, -and the declaration of $v$ is not an initializing variable declaration. +It is a +\Error{compile-time error} if the static type of $e$ is not assignable to +the declared type of $v$. +%% TODO(eernst): Revise when flow analysis is added. \commentary{% -It is also a compile-time error to assign to a final local variable +If a local variable $v$ is \FINAL{} and not \LATE, +it is not a compile-time error if the declaration of $v$ is +not an initializing variable declaration, +but an expression that gives rise to evaluation of $v$ +is a compile-time error unless flow analysis shows that +the variable is guaranteed to have been initialized. +Similarly, an expression that gives rise to an assignment to $v$ +is a compile-time error unless flow analysis shows that +it is guaranteed that the variable has \emph{not} been initialized.% +} + +\commentary{% +It is a compile-time error to assign to a local variable +which is \FINAL{} and not \LATE{} (\ref{assignment}).% } \LMHash{}% -It is a compile-time error if +Assume that $D$ is a local variable declaration with the modifier \LATE{} +that declares a variable $v$, +which has an initializing expression $e$. +It is a \Error{compile-time error} if $e$ contains an \AWAIT{} expression $a$ +(\ref{awaitExpressions}), +unless there is a function $f$ which is +the immediately enclosing function for $a$, +and $f$ is not the immediately enclosing function for $D$. + +\commentary{% +In other words, +the initializing expression cannot await an expression directly, +any await expressions must be nested inside some other function, +that is, a function literal.% +} + +\LMHash{}% +It is a \Error{compile-time error} if a local variable is referenced at a source code location that is before the end of its initializing expression, if any, and otherwise before the declaring occurrence of @@ -17712,15 +17780,39 @@ \subsection{Local Variable Declaration} \LMHash{}% The expression $e$ is evaluated to an object $o$. -Then, the variable $v$ is set to $o$. -% This error can occur due to implicit casts. +% The following error can occur due to implicit casts. A dynamic type error occurs -if the dynamic type of $o$ is not a subtype of the actual type +if the dynamic type of $o$ is not a subtype of the actual declared type (\ref{actualTypes}) of $v$. +Otherwise, the variable $v$ is bound to $o$. -% The local variable discussion does not mention how to read/write locals. -% Consider spelling this out, in terms of storage. +\LMHash{}% +Let $D$ be a \LATE{} and \FINAL{} local variable declaration +that declares a variable $v$. +If an object $o$ is assigned to $v$ +in a situation where $v$ is unbound +then $v$ is bound to $o$. +If an object $o$ is assigned to $v$ +in a situation where $v$ is bound to an object $o'$ +then a dynamic error occurs +(\commentary{it does not matter whether $o$ is the same object as $o'$}). + +\commentary{% +Note that this includes the implicit initializing writes induced by +evaluating the variable. +Hence, the following program encounters a dynamic error +when it evaluates \code{x}, +just before it would call \code{print}.% +} + +\begin{dartCode} +\VOID\ main() \{ + int i = 0; + \LATE\ \FINAL\ int x = i++ == 0 ? x + 1 : 0; + print(x); +\} +\end{dartCode} \subsection{Local Function Declaration} @@ -21151,7 +21243,7 @@ \subsection{Subtypes} may find the meaning of the given notation obvious, but we still need to clarify a few details about how to handle syntactically different denotations of the same type, -and how to choose the right initial environment, $\Gamma$. +and how to choose the right initial environment, $\Delta$. % For a reader who is not familiar with the notation used in this section, the explanations given here should suffice to clarify what it means, @@ -21254,7 +21346,7 @@ \subsection{Subtypes} \RuleTwo{\SrnRightPromotedVariable}{Right Promoted Variable}{S}{X}{S}{T}{% S}{X \& T} \Rule{\SrnRightFutureOrB}{Right FutureOr B}{S}{T}{S}{\code{FutureOr<$T$>}} - \Rule{\SrnLeftVariableBound}{Left Variable Bound}{\Gamma(X)}{T}{X}{T} + \Rule{\SrnLeftVariableBound}{Left Variable Bound}{\Delta(X)}{T}{X}{T} \end{minipage} \begin{minipage}[c]{0.49\textwidth} \Axiom{\SrnTypeVariableReflexivityA}{Left Promoted Variable A}{X \& S}{X} @@ -21267,26 +21359,26 @@ \subsection{Subtypes} % \ExtraVSP \RuleRawRaw{\SrnPositionalFunctionType}{Positional Function Types}{% - \Gamma' = \Gamma\uplus\{X_i\mapsto{}B_i\,|\,1 \leq i \leq s\} & - \Subtype{\Gamma'}{S_0}{T_0} \\ + \Delta' = \Delta\uplus\{X_i\mapsto{}B_i\,|\,1 \leq i \leq s\} & + \Subtype{\Delta'}{S_0}{T_0} \\ n_1 \leq n_2 & n_1 + k_1 \geq n_2 + k_2 & - \forall j \in 1 .. n_2 + k_2\!:\;\Subtype{\Gamma'}{T_j}{S_j}}{% + \forall j \in 1 .. n_2 + k_2\!:\;\Subtype{\Delta'}{T_j}{S_j}}{% \begin{array}{c} - \Gamma\vdash\RawFunctionTypePositional{S_0}{X}{B}{s}{S}{n_1}{k_1}\;<:\;\\ + \Delta\vdash\RawFunctionTypePositional{S_0}{X}{B}{s}{S}{n_1}{k_1}\;<:\;\\ \RawFunctionTypePositional{T_0}{X}{B}{s}{T}{n_2}{k_2} \end{array}} \ExtraVSP\ExtraVSP \RuleRawRaw{\SrnNamedFunctionType}{Named Function Types}{% - \Gamma' = \Gamma\uplus\{X_i\mapsto{}B_i\,|\,1 \leq i \leq s\} & - \Subtype{\Gamma'}{S_0}{T_0} & - \forall j \in 1 .. n\!:\;\Subtype{\Gamma'}{T_j}{S_j} \\ + \Delta' = \Delta\uplus\{X_i\mapsto{}B_i\,|\,1 \leq i \leq s\} & + \Subtype{\Delta'}{S_0}{T_0} & + \forall j \in 1 .. n\!:\;\Subtype{\Delta'}{T_j}{S_j} \\ \{\,\List{y}{n+1}{n+k_2}\,\} \subseteq \{\,\List{x}{n+1}{n+k_1}\,\} \\ \forall p \in 1 .. k_2, q \in 1 .. k_1:\quad - y_{n+p} = x_{n+q}\quad\Rightarrow\quad\Subtype{\Gamma'}{T_{n+p}}{S_{n+q}}}{% + y_{n+p} = x_{n+q}\quad\Rightarrow\quad\Subtype{\Delta'}{T_{n+p}}{S_{n+q}}}{% \begin{array}{c} - \Gamma\vdash\RawFunctionTypeNamed{S_0}{X}{B}{s}{S}{n}{x}{k_1}\;<:\;\\ - \RawFunctionTypeNamed{T_0}{X}{B}{s}{T}{n}{y}{k_2} + \Delta\vdash\RawFunctionTypeNamed{S_0}{X}{B}{s}{S}{n}{x}{k_1}{r}\;<:\;\\ + \RawFunctionTypeNamed{T_0}{X}{B}{s}{T}{n}{y}{k_2}{r} \end{array}} % \ExtraVSP @@ -21414,24 +21506,24 @@ \subsubsection{Subtype Rules} \LMHash{}% The rules in Figure~\ref{fig:subtypeRules} use -the symbol \Index{$\Gamma$} to denote the given knowledge about the +the symbol \Index{$\Delta$} to denote the given knowledge about the bounds of type variables. -$\Gamma$ is a partial function that maps type variables to types. +$\Delta$ is a partial function that maps type variables to types. At a given location where the type variables in scope are \TypeParametersStd{} (\commentary{as declared by enclosing classes and/or functions}), we define the environment as follows: -$\Gamma = \{\,X_1 \mapsto B_1,\ \ldots\ X_s \mapsto B_s\,\}$. +$\Delta = \{\,X_1 \mapsto B_1,\ \ldots\ X_s \mapsto B_s\,\}$. \commentary{% -That is, $\Gamma(X_1) = B_1$, and so on, -and $\Gamma$ is undefined when applied to a type variable $Y$ +That is, $\Delta(X_1) = B_1$, and so on, +and $\Delta$ is undefined when applied to a type variable $Y$ which is not in $\{\,\List{X}{1}{s}\,\}$.% } When the rules are used to show that a given subtype relationship exists, -this is the initial value of $\Gamma$. +this is the initial value of $\Delta$. \LMHash{}% -If a generic function type is encountered, an extension of $\Gamma$ is used, +If a generic function type is encountered, an extension of $\Delta$ is used, as shown in the rules~\SrnPositionalFunctionType{} and~\SrnNamedFunctionType{} of Figure~\ref{fig:subtypeRules}. @@ -21488,9 +21580,9 @@ \subsubsection{Being a subtype} \LMHash{}% A type $S$ is shown to be a \Index{subtype} of another type $T$ -in an environment $\Gamma$ by providing +in an environment $\Delta$ by providing an instantiation of a rule $R$ whose conclusion is -\IndexCustom{\SubtypeStd{S}{T}}{$\Gamma$@\SubtypeStd{S}{T}}, +\IndexCustom{\SubtypeStd{S}{T}}{$\Delta$@\SubtypeStd{S}{T}}, along with rule instantiations showing each of the premises of $R$, continuing until a rule with no premises is reached. @@ -21616,11 +21708,11 @@ \subsubsection{Informal Subtype Rule Descriptions} a subtype of \code{FutureOr<$T$>}. Another example is the wording in rule~\SrnReflexivity{}: -``\ldots{} in any environment $\Gamma$'', +``\ldots{} in any environment $\Delta$'', which indicates that the rule can be applied no matter which bindings of type variables to bounds there exist in the environment. It should be noted that the environment matters even with rules -where it is simply stated as a plain $\Gamma$ in the conclusion +where it is simply stated as a plain $\Delta$ in the conclusion and in one or more premises, because the proof of those premises could, directly or indirectly, include the application of a rule where the environment is used. @@ -21628,7 +21720,7 @@ \subsubsection{Informal Subtype Rule Descriptions} \def\Item#1#2{\item[#1]{\textbf{#2:}}} \begin{itemize} \Item{\SrnReflexivity}{Reflexivity} - Every type is a subtype of itself, in any environment $\Gamma$. + Every type is a subtype of itself, in any environment $\Delta$. In the following rules except for a few, the rule is also valid in any environment and the environment is never used explicitly, @@ -21679,7 +21771,7 @@ \subsubsection{Informal Subtype Rule Descriptions} \Item{\SrnLeftVariableBound}{Left Variable Bound} The type variable $X$ is a subtype of a type $T$ if the bound of $X$ - (as specified in the current environment $\Gamma$) + (as specified in the current environment $\Delta$) is a subtype of $T$. \Item{\SrnRightFunction}{Right Function} Every function type is a subtype of the type \FUNCTION. @@ -21699,7 +21791,7 @@ \subsubsection{Informal Subtype Rule Descriptions} is covered by letting $k_2 = 0$ respectively $k_1 = k_2 = 0$. For every subtype relation considered in this rule, the formal type parameters of $F_1$ and $F_2$ must be taken into account - (as reflected in the use of the extended environment $\Gamma'$). + (as reflected in the use of the extended environment $\Delta'$). We can assume without loss of generality that the names of type variables are pairwise identical, because we consider types of generic functions to be equivalent under @@ -21764,14 +21856,14 @@ \subsubsection{Additional Subtyping Concepts} \LMLabel{additionalSubtypingConcepts} \LMHash{}% -$S$ is a \Index{supertype} of $T$ in a given environment $\Gamma$, +$S$ is a \Index{supertype} of $T$ in a given environment $\Delta$, written \SupertypeStd{S}{T}, if{}f \SubtypeStd{T}{S}. \LMHash{}% A type $T$ \Index{may be assigned} -to a type $S$ in an environment $\Gamma$, +to a type $S$ in an environment $\Delta$, written \AssignableStd{S}{T}, if{}f either \SubtypeStd{S}{T} or \SubtypeStd{T}{S}. In this case we say that the types $S$ and $T$ are @@ -22881,7 +22973,7 @@ \section*{Appendix: Algorithmic Subtyping} \begin{minipage}[c]{0.49\textwidth} \RuleRaw{\AppSrnReflexivity}{Reflexivity}{S\mbox{ not composite}}{S}{S} \Rule{\AppSrnTypeVariableReflexivityC}{Type Variable Reflexivity B}{X}{T}{X}{X \& T} - \Rule{\AppSrnRightFutureOrC}{Right FutureOr C}{\Gamma(X)}{\code{FutureOr<$T$>}}{X}{\code{FutureOr<$T$>}} + \Rule{\AppSrnRightFutureOrC}{Right FutureOr C}{\Delta(X)}{\code{FutureOr<$T$>}}{X}{\code{FutureOr<$T$>}} \end{minipage} \begin{minipage}[c]{0.49\textwidth} \Axiom{\AppSrnTypeVariableReflexivityB}{Type Variable Reflexivity}{X}{X} From 218ac7f63cda933c3474d23de343643f1ae324ca Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 27 Sep 2022 12:14:27 +0200 Subject: [PATCH 04/15] Remove duplicate definition of DefEquals --- specification/dart.sty | 6 ------ 1 file changed, 6 deletions(-) diff --git a/specification/dart.sty b/specification/dart.sty index adabd48e87..e14e9b2a2c 100644 --- a/specification/dart.sty +++ b/specification/dart.sty @@ -481,12 +481,6 @@ \newcommand{\LowerBoundType}[2]{% \ensuremath{\LowerBoundTypeName(\code{{#1},\,\,{#2}})}} -\newcommand{\DefEquals}[2]{\ensuremath{{#1}\stackrel{\vartriangle}{=}{#2}}} -\newcommand{\DefEqualsNewline}[2]{ - \ensuremath{{#1}\stackrel{\vartriangle}{=}}\\ - \ensuremath{{#2}}% -} - % ---------------------------------------------------------------------- % Support for hash valued Location Markers From 863bc189dca2de5e8959ae52f63ee103dc105eb8 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 27 Sep 2022 13:21:29 +0200 Subject: [PATCH 05/15] WIP --- specification/dartLangSpec.tex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index c12c062999..6a76be81ca 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -24,7 +24,13 @@ % CHANGES % ======= % -% Significant changes to the specification. +% Significant changes to the specification. Note that the versions specified +% below indicate the current tool chain version when those changes were made. +% In practice, new features have always been integrated into the language +% specification (this document) a while after the change was accepted into +% the language and implemented. As of September 2022, the upcoming version of +% the language which is being specified is indicated by a version number in +% parentheses after the tool chain version. % % Note that the version numbers used below (up to 2.15) were associated with % the currently released language and tools at the time of the spec change, From 994790887d197f92c91346afed5b5a2ec75cda61 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 27 Sep 2022 13:22:08 +0200 Subject: [PATCH 06/15] WIP --- specification/dartLangSpec.tex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 6a76be81ca..df0da940aa 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -52,6 +52,8 @@ % Dec 2022 % - Change the definition of the type function 'flatten' to resolve soundness % issue, cf. SDK issue #49396. +% - Introducing null-safety related changes to the sections about variables +% and local variables. % - Change 'primitive operator ==' to 'primitive equality', and include % constraints on `hashCode` corresponding to the ones we have on `==`. % From b244329302d723de349efd75f298386c55120970 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 28 Sep 2022 13:27:13 +0200 Subject: [PATCH 07/15] Review response --- specification/dart.sty | 183 +++++++++++---- specification/dartLangSpec.tex | 402 ++++++++++++++++++--------------- 2 files changed, 356 insertions(+), 229 deletions(-) diff --git a/specification/dart.sty b/specification/dart.sty index e14e9b2a2c..f7ff41474a 100644 --- a/specification/dart.sty +++ b/specification/dart.sty @@ -136,6 +136,7 @@ \newcommand{\Case}[1]{\textbf{Case }$\langle\hspace{0.1em}${#1}$\hspace{0.1em}\rangle$\textbf{.}} \newcommand{\EndCase}{\mbox{}\hfill$\scriptscriptstyle\Box$\xspace} +% Used for source code examples. \newenvironment{dartCode}[1][!ht]{% \def\@programcr{\@addfield\strut}% \let\\=\@programcr% @@ -144,6 +145,7 @@ \vspace{1em}% }{\normalcolor\vspace{1em}} +% Used for normative code snippets (mainly desugaring). \newenvironment{normativeDartCode}[1][!ht]{% \def\@programcr{\@addfield\strut}% \let\\=\@programcr% @@ -152,6 +154,9 @@ \vspace{1em}% }{\normalcolor\vspace{1em}} +% Used for meta-level code, such as the code transformations used +% to specify the semantics of "null shorting" in expressions like +% `a?.b.c`. \newenvironment{metaLevelCode}[1][!ht]{% \def\@programcr{\@addfield\strut}% \let\\=\@programcr% @@ -206,20 +211,37 @@ \newcommand{\PairList}[4]{\ensuremath{% {#1}_{#3}\ {#2}_{#3},\,\ldots,\ {#1}_{#4}\ {#2}_{#4}}} -% Used to specify named arguments. -% Parameters: Parameter name, argument name, index at start, index at end. +% A sequence of labeled arguments with the same label and expression, +% only differing by subscript. +% Parameters: Argument label, argument expression, start index, +% end index. +% +% For example, \NamedArgumentList{n}{e}{1}{k} yields approximately +% "n1: e1, n2: e2, ... nk: ek". \newcommand{\NamedArgumentList}[4]{\PairList{#1}{\!\!:\,\,{#2}}{#3}{#4}} -% Used to specify an argument list including positional and named arguments. -% Parameters: Argument name, number of positional arguments, named parameter -% name, number of named arguments. +% A sequence of unlabeled and labeled arguments with the same expression and +% (for all labeled arguments) the same label, only differing by subscript. +% Parameters: Argument name, number of positional arguments, labeled parameter +% label, number of labeled arguments. +% +% For example, \ArgumentList{a}{n}{x}{k} yields approximately +% "a1, .. an, xn+1: an+1, .. xn+k: an+k". \newcommand{\ArgumentList}[4]{% \List{#1}{1}{#2},\ \NamedArgumentList{#3}{#1}{{#2}+1}{{#2}+{#4}}} -% Used to specify a standard argument list. +% Used to specify a standard argument list, that is, an argument list +% which uses the symbols that we prefer to use for that purpose +% whenever possible. +% +% Approximately "a1 .. an, xn+1: an+1 .. xn+k: an+k". \newcommand{\ArgumentListStd}{\ArgumentList{a}{n}{x}{k}} -% Used to specify a standard type argument list. +% Used to specify a standard type argument list, that is, a type +% argument list which uses the symbols we prefer to use for that +% purpose whenever possible. +% +% Approximately "A1 .. Ar". \newcommand{\TypeArgumentListStd}{\List{A}{1}{r}} % Used to specify a list of tuples of the form $(K_j, V_j)$ which are @@ -256,7 +278,11 @@ \newcommand{\TypeParametersNoBounds}[2]{\ensuremath{% {#1}_1\,\EXTENDS\,\ldots,\ \ldots,\ {#1}_{#2}\,\EXTENDS\,\ldots}} -% For consistency, we may as well use this whenever possible. +% Used to specify a standard type parameter list, that is, a type +% parameter declaration list which uses the symbols we prefer to use +% for that purpose whenever possible. +% +% Approximately "X1 extends B1, .. Xs extends Bs". \newcommand{\TypeParametersStd}{\TypeParameters{X}{B}{s}} % Used to specify comma separated lists of pairs of symbols @@ -288,83 +314,140 @@ % Used to specify function type parameter lists with positional optionals. % Arguments: Parameter type, number of required parameters, -% number of optional parameters. -\newcommand{\FunctionTypePositionalArguments}[3]{% +% number of optional parameters. +% +% For example, \FunctionTypePositionalParameters{T}{n}{k} yields +% approximately "T1, .. Tn, [Tn+1, .. Tn+k]". +\newcommand{\FunctionTypePositionalParameters}[3]{% \List{#1}{1}{#2},\ [\List{#1}{{#2}+1}{{#2}+{#3}}]} -\newcommand{\FunctionTypePositionalArgumentsStd}{% - \FunctionTypePositionalArguments{T}{n}{k}} +% Used to specify a standard positional function type, that is, a function +% type with positional optional parameters which uses the symbols we prefer +% to use for that purpose whenever possible. +% +% Approximately "T1, .. Tn, [Tn+1, .. Tn+k]". +\newcommand{\FunctionTypePositionalParametersStd}{% + \FunctionTypePositionalParameters{T}{n}{k}} + +% Used to specify function type parameter lists with named optionals. +% Arguments: Parameter type, number of required parameters, +% name of optional parameters, number of optional parameters. +% +% For example \FunctionTypeNamedParameters{T}{n}{x}{k}{r} yields approximately +% "T1, .. Tn, {rn+1 Tn+1 xn+1, .. rn+k Tn+k xn+k}". +\newcommand{\FunctionTypeNamedParameters}[5]{% + \List{#1}{1}{#2},\ \{\TripleList{#5}{#1}{#3}{{#2}+1}{{#2}+{#4}}\}} + +% Variant of \FunctionTypeNamedParameters that uses the standard symbols, +% that is, a list of function type parameter declarations with named +% parameters which uses the symbols that we prefer to use for that purpose +% whenever possible. +% +% Approximately "T1, .. Tn, {rn+1 Tn+1 xn+1, .. rn+k Tn+k xn+k}". +\newcommand{\FunctionTypeNamedParametersStd}{% + \FunctionTypeNamedParameters{T}{n}{x}{k}{r}} % Used to specify function types with positional optionals: % Arguments: Return type, spacer, type parameter name, bound name, % number of type parameters, parameter type, number of required parameters, % number of optional parameters. +% +% For example, \FunctionTypePositional{R}{ }{X}{B}{s}{T}{n}{k} yields +% approximately +% "R Function(T1, .. Tn, [Tn+1, .. Tn+k])". \newcommand{\FunctionTypePositional}[8]{% \FunctionType{#1}{#2}{#3}{#4}{#5}{% - \FunctionTypePositionalArguments{#6}{#7}{#8}}} + \FunctionTypePositionalParameters{#6}{#7}{#8}}} % Same as \FunctionTypePositional except suitable for inline usage, % hence omitting the spacer argument. \newcommand{\RawFunctionTypePositional}[7]{% \RawFunctionType{#1}{#2}{#3}{#4}{% - \FunctionTypePositionalArguments{#5}{#6}{#7}}} + \FunctionTypePositionalParameters{#5}{#6}{#7}}} + +% A variant of \FunctionTypePositional that uses the standard symbols, +% that is, a function type with positional optional parameters which +% uses the symbols that we prefer to use for that purpose whenever +% possible. +% +% For example, \FunctionTypePositionalStd{R} yields approximately +% "R Function(T1, T2, .. Tn, [Tn+1 .. Tn+k])". +\newcommand{\FunctionTypePositionalStd}[1]{% + \FunctionTypePositional{#1}{ }{X}{B}{s}{T}{n}{k}} -% Used to specify function type parameter lists with named optionals. -% Arguments: Parameter type, number of required parameters, -% name of optional parameters, number of optional parameters, -% name of `required` symbol. -\newcommand{\FunctionTypeNamedArguments}[5]{% - \List{#1}{1}{#2},\ \{\TripleList{#5}{#1}{#3}{{#2}+1}{{#2}+{#4}}\}} - -\newcommand{\FunctionTypeNamedArgumentsStd}{% - \FunctionTypeNamedArguments{T}{n}{x}{k}{r}} +% Same as \FunctionTypePositionalStd except suitable for inline usage, +% hence omitting the spacer argument. +\newcommand{\RawFunctionTypePositionalStd}[1]{% + \RawFunctionTypePositional{#1}{X}{B}{s}{T}{n}{k}} + +% Same as \FunctionTypePositionalStd except that it includes a newline, hence +% suitable for function types that are too long to fit in one line. +\newcommand{\FunctionTypePositionalStdCr}[1]{% + \FunctionTypePositional{#1}{\\}{X}{B}{s}{T}{n}{k}} % Used to specify function types with named parameters: % Arguments: Return type, spacer, type parameter name, bound name, % number of type parameters, parameter type, number of required parameters, -% name of optional parameters, number of optional parameters, -% name of `required` symbol. +% name of optional parameters, number of optional parameters. +% The name of the `required` symbol is always `r` (because we can't have +% 10 arguments in a LaTeX command, and `r` is always OK in practice). +% +% For example, \FunctionTypeNamed{R}{ }{X}{B}{s}{T}{n}{x}{k} yields +% approximately "R Function( +% T1, T2, .. Tn, {rn+1 Tn+1 xn+1, .. rn+k Tn+k xn+k])". \newcommand{\FunctionTypeNamed}[9]{% \FunctionType{#1}{#2}{#3}{#4}{#5}{\\ - \mbox{}\qquad\FunctionTypeNamedArguments{#6}{#7}{#8}{#9}{#10}}} + \mbox{}\qquad\FunctionTypeNamedParameters{#6}{#7}{#8}{#9}{r}}} -% Same as \FunctionType except suitable for inline usage, hence omitting +% Same as \FunctionTypeNamed except suitable for inline usage, hence omitting % the spacer argument. -\newcommand{\RawFunctionTypeNamed}[9]{% +\newcommand{\RawFunctionTypeNamed}[8]{% \RawFunctionType{#1}{#2}{#3}{#4}{% - \FunctionTypeNamedArguments{#5}{#6}{#7}{#8}{#9}}} + \FunctionTypeNamedParameters{#5}{#6}{#7}{#8}{r}}} + +% A variant of \FunctionTypeNamed that uses the standard symbols, +% that is, a function type with positional optional parameters which +% uses the symbols that we prefer to use for that purpose whenever +% possible. +% +% For example, \FunctionTypeNamedStd{R} yields approximately +% "R Function( +% T1, T2, .. Tn, {rn+1 Tn+1 xn+1, .. rn+k Tn+k xn+k})". +\newcommand{\FunctionTypeNamedStd}[1]{% + \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}} + +% Same as \FunctionTypeNamedStd except suitable for inline usage, hence +% omitting the spacer argument. +\newcommand{\RawFunctionTypeNamedStd}[1]{% + \RawFunctionTypeNamed{#1}{X}{B}{s}{T}{n}{x}{k}{r}} + +% Same as \FunctionTypeNamedStd except that it includes a newline, hence +% suitable for function types that are too long to fit in one line. +\newcommand{\FunctionTypeNamedStdCr}[1]{% + \FunctionTypeNamed{#1}{\\}{X}{B}{s}{T}{n}{x}{k}} % Used to specify function types with no optional parameters: % Arguments: Return type, spacer, type parameter name, bound name, % number of type parameters, parameter type, % number of parameters (all required). +% +% For example, \FunctionTypeAllRequired{R}{ }{X}{B}{s}{T}{n} yields +% approximately "R Function(T1, T2, .. Tn)". \newcommand{\FunctionTypeAllRequired}[7]{% \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7}}} -\newcommand{\FunctionTypePositionalStd}[1]{% - \FunctionTypePositional{#1}{ }{X}{B}{s}{T}{n}{k}} - -\newcommand{\RawFunctionTypePositionalStd}[1]{% - \RawFunctionTypePositional{#1}{X}{B}{s}{T}{n}{k}} - -\newcommand{\FunctionTypeNamedStd}[1]{% - \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}{r}} - -\newcommand{\RawFunctionTypeNamedStd}[1]{% - \RawFunctionTypeNamed{#1}{X}{B}{s}{T}{n}{x}{k}{r}} - +% A variant of \FunctionTypeAllRequired that uses the standard symbols, +% that is, a function type with positional optional parameters which +% uses the symbols that we prefer to use for that purpose whenever +% possible. +% +% For example, \FunctionTypeAllRequiredStd{R} yields approximately +% "R Function(T1, T2, .. Tn)". \newcommand{\FunctionTypeAllRequiredStd}[1]{% \FunctionTypeAllRequired{#1}{ }{X}{B}{s}{T}{n}} -\newcommand{\FunctionTypePositionalStdCr}[1]{% - \FunctionTypePositional{#1}{\\}{X}{B}{s}{T}{n}{k}} - -\newcommand{\FunctionTypeNamedStdCr}[1]{% - \FunctionTypeNamed{#1}{\\}{X}{B}{s}{T}{n}{x}{k}{r}} - -\newcommand{\FunctionTypeNamedStdArgCr}[1]{% - \FunctionTypeNamedArgCr{#1}{ }{X}{B}{s}{T}{n}{x}{k}{r}} - +% Same as \FunctionTypeAllRequiredStd except that it includes a newline, hence +% suitable for function types that are too long to fit in one line. \newcommand{\FunctionTypeAllRequiredStdCr}[1]{% \FunctionTypeAllRequired{#1}{\\}{X}{B}{s}{T}{n}} diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index df0da940aa..3477e11e61 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -1362,7 +1362,7 @@ \section{Variables} no initializing expression and a type which is not nullable (\ref{typeNullability}), unless the variable declaration has -the modifier \LATE{} or \EXTERNAL. +the modifier \LATE{} or the modifier \EXTERNAL. \LMHash{}% A \IndexCustom{non-local variable}{variable!non-local} @@ -1379,12 +1379,17 @@ \section{Variables} or a \Error{compile-time error} occurs. \commentary{% -An initializing expression of a constant variable occurs in a constant context -(\ref{constantContexts}), -which means that \CONST{} modifiers need not be specified explicitly. -We need not specify that it is a compile-time error for a constant variable -to have the modifier \LATE, -because such declarations are not derivable syntactically.% +An initializing expression $e$ of a constant variable declaration +occurs in a constant context +(\ref{constantContexts}). +This means that \CONST{} modifiers in $e$ need not be specified explicitly. + +It is grammatically impossible for a constant variable declaration +to have the modifier \LATE. +However, even if it had been grammatically possible, +a \LATE{} constant variable would still have to be a compile-time error, +because being a compile-time constant is inherently incompatible +with being computed late.% } \LMHash{}% @@ -1409,32 +1414,43 @@ \subsection{Implicitly Induced Getters and Setters} (\ref{localVariableDeclaration}) do not induce getters or setters.% } -For each form of declaration mentioned, -the modifier \STATIC{} may be present or absent. \LMHash{}% -A variable declaration of one of the forms -\code{\LATE?\,\,$T$\,\,\id;} -\code{\LATE?\,\,$T$\,\,\id{} = $e$;} -\code{\CONST\,\,$T$\,\,\id{} = $e$;} -\code{\LATE?\,\,\FINAL\,\,$T$\,\,\id;} or -\code{\LATE?\,\,\FINAL\,\,$T$\,\,\id{} = $e$;} -where $T$ is a type -implicitly induces a getter (\ref{getters}) with header -\code{$T$\,\,\GET\,\,\id}, +Consider a variable declaration of one of the forms + +\begin{itemize} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL?\,\,$T$\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL?\,\,$T$\,\,\id{} = $e$;} +\item \code{\STATIC?\,\,\CONST\,\,$T$\,\,\id{} = $e$;} +\end{itemize} + +\noindent +where $T$ is a type, \id{} is an identifier, +and \lit{?} indicates that the given modifier may be present or absent. +Each of these declarations implicitly induces a getter +(\ref{getters}) +with the header \code{$T$\,\,\GET\,\,\id}, whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}). -In these cases the static type of \id{} is $T$. +In these cases the declared type of \id{} is $T$. \LMHash{}% A variable declaration of one of the forms -\code{\LATE?\,\,\VAR\,\,\id;} or -\code{\LATE?\,\,\FINAL\,\,\id;} -implicitly induces a getter with header + +\begin{itemize} +\item \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL\,\,\id{} = $e$;} +\item \code{\STATIC?\,\,\CONST\,\,\id{} = $e$;} +\end{itemize} + +\noindent +implicitly induces a getter with the header \code{\DYNAMIC\,\,\GET\,\,\id}, whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}). -In these cases, the static type of \id{} is \DYNAMIC{} +In these cases, the declared type of \id{} is \DYNAMIC{} (\ref{typeDynamic}). \commentary{% @@ -1449,29 +1465,22 @@ \subsection{Implicitly Induced Getters and Setters} } \LMHash{}% -A variable declaration of one of the forms -\code{\LATE?\,\,\VAR\,\,\id{} = $e$;} -\code{\CONST\,\,\id{} = $e$;} -or \code{\LATE?\,\,\FINAL\,\,\id{} = $e$;} -implicitly induces a getter with header -\code{$T$\,\,\GET\,\,\id} -where $T$ is the static type of $e$. -The semantics of an invocation of such getters is described below -(\ref{evaluationOfImplicitVariableGetters}). -In these cases, the static type of \id{} is $T$. +A mutable variable declaration of one of the forms -\LMHash{}% -A mutable variable declaration of the form -\code{\LATE?\,\,$T$\,\,\id;} or -\code{\LATE?\,\,$T$\,\,\id{} = $e$;} -implicitly induces a setter (\ref{setters}) with header +\begin{itemize} +\item \code{\STATIC?\,\,\LATE?\,\,$T$\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,$T$\,\,\id{} = $e$;} +\end{itemize} + +\noindent +implicitly induces a setter (\ref{setters}) with the header \code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)}, whose execution sets the value of \id{} to the incoming argument $x$. \LMHash{}% A variable declaration of the form -\code{\LATE\,\,\FINAL\,\,$T$\,\,\id;} -implicitly induces a setter (\ref{setters}) with header +\code{\STATIC?\,\,\LATE\,\,\FINAL\,\,$T$\,\,\id;} +implicitly induces a setter (\ref{setters}) with the header \code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)}. If this setter is executed in a situation where the variable \id{} has not been bound, @@ -1490,8 +1499,8 @@ \subsection{Implicitly Induced Getters and Setters} \LMHash{}% A mutable variable declaration of the form -\code{\LATE?\,\,\VAR\,\,\id;} -implicitly induces a setter with header +\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} +implicitly induces a setter with the header \code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, whose execution sets the value of \id{} to the incoming argument $x$. @@ -1503,16 +1512,15 @@ \subsection{Implicitly Induced Getters and Setters} \LMHash{}% A mutable variable declaration of the form -\code{\LATE?\,\,\VAR\,\,\id{} = $e$;} -implicitly induces a setter with header -\code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)} -where $T$ is the static type of $e$, +\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} +implicitly induces a setter with the header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, whose execution sets the value of \id{} to the incoming argument $x$. \LMHash{}% A variable declaration of the form -\code{\LATE\,\,\FINAL\,\,\id;} -implicitly induces a setter with header +\code{\STATIC?\,\,\LATE\,\,\FINAL\,\,\id;} +implicitly induces a setter with the header \code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}. An execution of said setter in a situation where the variable \id{} has not been bound @@ -1544,8 +1552,8 @@ \subsection{Implicitly Induced Getters and Setters} the body scope of the immediately enclosing class. \LMHash{}% -Let \id{} be variable declared in an initializing variable declaration, -and let $e$ be the associated initializing expression. +Let \id{} be a variable declared by a variable declaration +that has an initializing expression $e$. It is a \Error{compile-time error} if the static type of $e$ is not assignable to the declared type of \id. It is a \Error{compile-time error} if a final instance variable @@ -1563,11 +1571,13 @@ \subsection{Implicitly Induced Getters and Setters} A non-late static final variable \id{} does not induce a setter, so unless a setter named \code{\id=} can be found by lexical lookup (\ref{lexicalLookup}), +or lexical lookup yields nothing, and the location has access to \THIS, +and the enclosing class or mixin has a setter named \code{\id=}, it is a compile-time error to assign to \id. Similarly, assignment to a non-late final instance variable \id{} is a compile-time error, -unless a setter named \code{\id=} can be found by lexical lookup, +unless a setter named \code{\id=} can be found as above, or the receiver has type \DYNAMIC. \id{} can be initialized in its declaration or in initializer lists, but initialization and assignment is not the same thing. @@ -1577,11 +1587,25 @@ \subsection{Implicitly Induced Getters and Setters} } \LMHash{}% -Consider a variable \id{} with no initializing expression +Consider a variable \id{} whose declaration does not have the modifier \LATE. -If this is not a compile-time error then \id{} has the null object -(\ref{null}) -as its initial value. +Assume that \id{} does not have an initializing expression, +and it is not initialized by an initializing formal +(\ref{generativeConstructors}), +nor by an element in a constructor initializer list +(\ref{initializerLists}). +The initial value of \id{} is then the null object +(\ref{null}). + +\commentary{% +Note that there are many situations where such a variable declaration +is a compile-time error +in which case we do not specify any of its properties, +and in particular it makes no sense to say +that it has a particular initial value. +For example, it is an error if a final instance variable +is not initialized by one of the above mechanisms.% +} \LMHash{}% Otherwise, variable initialization proceeds as follows: @@ -1639,63 +1663,149 @@ \subsection{Implicitly Induced Getters and Setters} \subsection{Evaluation of Implicit Variable Getters} \LMLabel{evaluationOfImplicitVariableGetters} +\LMHash{}% +We introduce two specific kinds of getters in order to specify +the behavior of various kinds of variables +without duplicating the specification of their common behaviors. + +\LMHash{}% +A +\IndexCustom{late-initialized getter}{getter!late-initialized} +is a getter $g$ which is implicitly induced by a non-local variable $v$ +that has an initializing expression $e$. +\commentary{% +Note that only \emph{some} non-local variables with an initializing expression +induce a late-initialized getter, +and others induce other kinds of getters, as described below.% +} +An invocation of $g$ proceeds as follows: +If the variable $v$ has not been bound to an object then +$e$ is evaluated to an object $o$, +$v$ is bound to $o$, +and the evaluation of $g$ completes returning $o$. +If the evaluation of $e$ throws then +the invocation of $g$ completes throwing the same object and stack trace, +and no binding of $v$ to any object occurs. +An invocation of $g$ in a situation where $v$ has been bound to an object $o'$ +completes immediately, returning $o'$. + +\commentary{% +Consider a non-local variable declaration of the form +\code{\LATE\,\,\VAR\,\,x = $e$;}, +whose implicitly induced getter is late-initialized. +Perhaps surprisingly, +if the variable \code{x} has been bound to an object +when its getter is invoked for the first time, +$e$ will never be executed. +In other words, the initializing expression can be pre-empted.% +} + +\commentary{% +Also note that an initializing expression can have side effects +that are significant during initialization. +For example:% +} + +\begin{dartCode} +bool b = \TRUE; +int i = (() => (b = !b) ? (i = 10) : i + 1)(); +\\ +\VOID{} main() \{ + print(i); // '11'. +\} +\end{dartCode} + +\commentary{% +In this example, \code{main} invokes +the implicitly induced getter named \code{i}, +and the variable \code{i} has not been bound at this point. +Hence, evaluation of the initializing expression proceeds. +This causes \code{b} to be toggled to \FALSE, +which again causes \code{i + 1} to be evaluated. +This causes the getter \code{i} to be invoked again, +and it is still true that the variable has not been bound, +so the initializing expression is evaluated again. +This toggles \code{b} to \TRUE, +which causes \code{i = 10} to be evaluated, +which causes the implicitly induced setter named \code{i=} to be invoked, +and the most recent invocation of the getter \code{i} +returns 10. +This makes \code{i + 1} evaluate to 11, +and the variable is then bound to 11. +Finally, the invocation of the getter \code{i} in \code{main} +completes returning 11.% +} + +\commentary{% +This is a change from the semantics of older versions of Dart: +Throwing an exception during initializer evaluation no longer sets the +variable to \code{null}, +and reading the variable during initializer evaluation +no longer causes a dynamic error.% +} + +\LMHash{}% +A +\IndexCustom{late-uninitialized getter}{getter!late-uninitialized} +is a getter $g$ which is implicitly induced by a non-local variable $v$ +that does not have an initializing expression. +\commentary{% +Again, only \emph{some} non-local variables without an initializing expression +induce a late-uninitialized getter, as specified below.% +} +An invocation of $g$ proceeds as follows: +If the variable $v$ has not been bound to an object then a dynamic error occurs. +If $v$ has been bound to an object $o'$ then +the invocation of $g$ completes immediately, returning $o'$. + \LMHash{}% \BlindDefineSymbol{d, \id}% Let $d$ be the declaration of a non-local variable named \id. For brevity, we will refer to it below as `the variable \id' or `the variable $d$', or just as `\id' or `$d$'. +Execution of the implicitly induced getter of \id{} proceeds as follows: \LMHash{}% \Case{Non-late instance variable} If $d$ declares an instance variable which does not have the modifier \LATE, then the invocation of the implicit getter of \id{} evaluates to the object that \id{} is bound to. + +\commentary{% +Any situation where \id{} is unbound when this getter is evaluated +is a compile-time error, +so there is no need to specify a behavior for that situation.% +} \EndCase \LMHash{}% \Case{Late, initialized instance variable} -If $d$ declares an instance variable which has the modifier \LATE{} -and an initializing expression $e$, -then an invocation of the implicit getter of \id{} -in a situation where the variable \id{} has not been bound -will evaluate $e$ to an object $o$, -bind \id{} to $o$, -and complete returning $o$; -if the evaluation of $e$ throws then -the invocation of the getter throws the same object and stack trace. -An invocation of the implicit getter of \id{} -in a situation where the variable \id{} has been bound to an object $o'$ -evaluates to $o'$. - -\commentary{% -Consider an instance variable declaration of the form -\code{\LATE\,\,\VAR\,\,x = $e$;}. -Perhaps surprisingly, -if the variable \code{x} has been bound to an object -when its getter is invoked for the first time, -$e$ will never be executed. -Another example worth noting -is given below in the text about -a non-constant static variable with an initializer. -That example (i.e., the one with \code{bool\,\,b;} and \code{int\,\,i = ...;}) -works in the same manner when \code{i} is an instance variable.% -} +If $d$ declares an instance variable \id{} which has the modifier \LATE{} +and an initializing expression, +the implicitly induced getter of \id{} is a +late-initialized getter. +This determines the semantics of an invocation. \EndCase \LMHash{}% \Case{Late, uninitialized instance variable} -Consider the case where $d$ declares an instance variable -which has the modifier \LATE{} and no initializing expression. -Assume that the object denoted by \THIS{} was created with -a constructor invocation where said instance variable was initialized -by an initializing formal or by an initializer list element, -or that the corresponding setter named \code{\id=} has been executed -and completed without throwing. -In this case, an invocation of the implicit getter of \id{} -will evaluate to the object that \id{} is bound to. -Otherwise -(\commentary{when this variable has never been bound}), -the getter invocation incurs a dynamic error. +If $d$ declares an instance variable \id{} which has the modifier \LATE{} +and does not have an initializing expression, +the implicitly induced getter of \id{} is a +late-uninitialized getter. +This determines the semantics of an invocation. + +\commentary{% +In this case it is possible for \id{} to be unbound, +but there are also several ways to bind \id{} to an object: +A constructor can have an initializing formal +(\ref{generativeConstructors}) +or an initializer list entry +(\ref{initializerLists}) +that will initialize \id{}, +and the implicitly induced setter named \code{\id=} could +have been invoked and completed normally.% +} \EndCase \LMHash{}% @@ -1706,103 +1816,37 @@ \subsection{Evaluation of Implicit Variable Getters} \begin{itemize} \item \emph{Non-constant variable with an initializer.} - Consider the case where $d$ has one of the forms - \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;}, - \code{\STATIC?\,\,\LATE?\,\,\FINAL\,\,\id{} = $e$;}, or - \code{\STATIC?\,\,\LATE?\,\,\FINAL?\,\,$T$\,\,\id{} = $e$;}. - - The invocation of the implicitly induced getter of \id{} - in a situation where the variable \id{} has not been bound - will evaluate $e$ to an object $o$, bind \id{} to $o$, - and complete returning $o$; - if the evaluation of $e$ throws, - the invocation of the getter throws the same object and stack trace. - An invocation of the getter of \id{} - in a situation where the variable \id{} has been bound to an object $o'$ - completes returning $o'$. - + In the case where $d$ has an initializing expression and is not constant, + the implicitly induced getter of \id{} is a late-initialized getter. + This determines the semantics of an invocation. \commentary{% - Note that an initializing expression can have side effects - that are significant during initialization. - For example:% - } - -\begin{dartCode} -bool b = \TRUE; -int i = (() => (b = !b) ? (i = 10) : i + 1)(); -\\ -\VOID{} main() \{ - print(i); // '11'. -\} -\end{dartCode} - - \commentary{% - In this example, \code{main} invokes - the implicitly induced getter named \code{i}, - and the variable \code{i} has not been bound at this point. - Hence, evaluation of the initializing expression proceeds. - This causes \code{b} to be toggled to \FALSE, - which again causes \code{i + 1} to be evaluated. - This causes the getter \code{i} to be invoked again, - and it is still true that the variable has not been bound, - so the initializing expression is evaluated again. - This toggles \code{b} to \TRUE, - which causes \code{i = 10} to be evaluated, - which causes the implicitly induced setter named \code{i=} to be invoked, - and the most recent invocation of the getter \code{i} - returns 10. - This makes \code{i + 1} evaluate to 11, - and the variable is then bound to 11. - Finally, the invocation of the getter \code{i} in \code{main} - completes returning 11.% - } - - \commentary{% - Note that this is a change from the semantics older versions of Dart: - Throwing an exception during initializer evaluation no longer sets the - variable to \code{null}, - and reading the variable during initializer evaluation - no longer causes a dynamic error.% + Note that these static variables can be \emph{implicitly} late-initialized.% } \item \emph{Constant variable.} - If $d$ is of one of the forms - \code{\STATIC?\,\,\LATE?\,\,\CONST{} $v$ = $e$;} or - \code{\STATIC?\,\,\LATE?\,\,\CONST{} $T$ $v$ = $e$;}. - the result of the executing the implicitly induced getter is + If $d$ declares a constant variable with the initializing expression $e$, + the result of executing the implicitly induced getter is the value of the constant expression $e$. \commentary{% Note that a constant expression cannot depend on itself, so no cyclic references can occur.% } \item \emph{Variable without an initializer.} - Consider the case where $d$ has one of the forms - \code{\STATIC?\,\,\VAR\,\,\id;} or - \code{\STATIC?\,\,$T$\,\,\id;}. - The result of executing the implicitly induced getter of \id{} is + If $d$ declares a variable \id{} without an initializing expression + and does not have the modifier \LATE, + an invocation of the implicitly induced getter of \id{} evaluates to the object that \id{} is bound to. - + \commentary{% - This may be the initial value, that is, the null object - (the typed variant is an error unless $T$ is nullable). - Note that forms like \code{\FINAL\,\,\id;} and - \code{\FINAL\,\,$T$\,\,\id;} are irrelevant here: - They are syntax errors at the top level, - and instance variables were specified earlier in this section. - The forms \code{\STATIC\,\,\FINAL\,\,\id;} and - \code{\STATIC\,\,\FINAL\,\,$T$\,\,\id;} - are syntax errors as well.% + The variable is always bound to an object in this case. + This may be the null object, + which is the initial value of some variable declarations + covered by this case.% } - Consider the situation where $d$ has one of the forms - \code{\STATIC?\,\,\LATE\,\,\VAR\,\,\id;}, - \code{\STATIC?\,\,\LATE\,\,\FINAL\,\,\id;}, or - \code{\STATIC?\,\,\LATE\,\,\FINAL?\,\,$T$\,\,\id;}. - An execution of the implicitly induced getter of \id{} - in a situation where the variable \id{} is bound to an object $o$ - will complete returning $o$. - An execution of the implicitly induced getter of \id{} - in a situation where the variable \id{} is unbound - will incur a dynamic error. + If $d$ declares a variable \id{} without an initializing expression + and has the modifier \LATE, + the implicitly induced getter is a late-uninitialized getter. + This determines the semantics of an invocation. \end{itemize} % Reduce whitespace after itemized list: This is just an end symbol. @@ -17649,7 +17693,7 @@ \subsection{Local Variable Declaration} (\ref{intersectionTypes}), the declared type of $v$ is \code{X}. \commentary{% - In this case $v$ is immediately promoted + In this case $v$ is immediately promoted to \code{$X$\,\&\,$T$} (\ref{typePromotion}).% } \item @@ -17695,7 +17739,7 @@ \subsection{Local Variable Declaration} \commentary{% In other words, the initializing expression cannot await an expression directly, -any await expressions must be nested inside some other function, +any await expressions must be syntactically nested inside some other function, that is, a function literal.% } From c930867accab920b99e02a69cbe32f43860702ee Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 30 Sep 2022 18:23:16 +0200 Subject: [PATCH 08/15] Further improvements (introduce cases for different kinds of variables) --- specification/dartLangSpec.tex | 114 ++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 46 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 3477e11e61..b856f10e77 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -1393,19 +1393,25 @@ \section{Variables} } \LMHash{}% -A \IndexCustom{final variable}{variable!final} +An \IndexCustom{immutable variable}{variable!immutable} is a variable whose binding is fixed upon initialization; -a final variable \id{} will always refer to the same object +an immutable variable \id{} will always refer to the same object after \id{} has been initialized. -A variable is final if{}f its declaration includes +A variable is immutable if{}f its declaration includes the modifier \FINAL{} or the modifier \CONST. A \IndexCustom{mutable variable}{variable!mutable} -is a variable which is not final. +is a variable which is not immutable. \subsection{Implicitly Induced Getters and Setters} \LMLabel{implicitlyInducedGettersAndSetters} +%% TODO(eernst): When inference is specified, we should be able to conclude +%% that the cases with no declared type do not exist after type inference +%% (for instance `var x;` or `var x = e;`), and then we can replace all rules +%% about such cases by commentary saying that they may exist in the input, +%% but they are gone after type inference. + \LMHash{}% The following rules on implicitly induced getters and setters apply to all non-local variable declarations. @@ -1416,6 +1422,7 @@ \subsection{Implicitly Induced Getters and Setters} } \LMHash{}% +\Case{Getter: Variable with declared type} Consider a variable declaration of one of the forms \begin{itemize} @@ -1433,8 +1440,10 @@ \subsection{Implicitly Induced Getters and Setters} whose invocation evaluates as described below (\ref{evaluationOfImplicitVariableGetters}). In these cases the declared type of \id{} is $T$. +\EndCase \LMHash{}% +\Case{Getter: Variable with no declared type} A variable declaration of one of the forms \begin{itemize} @@ -1459,12 +1468,15 @@ \subsection{Implicitly Induced Getters and Setters} For example, an instance variable declaration of the form \code{\VAR\,\,x;} could have been transformed into \code{$T$\,\,x;} based on member signatures named \code{x} in superinterfaces -of the enclosing class. -Hence, the type \DYNAMIC{} is only used as mentioned above when -type inference fails to provide a different type.% +of the enclosing class, and +\code{\VAR\,x\,\,=\,\,$e$;} could have been transformed into +\code{$T$\,x\,\,=\,\,$e$;} +where $T$ is the static type of $e$.% } +\EndCase \LMHash{}% +\Case{Setter: Mutable variable with declared type} A mutable variable declaration of one of the forms \begin{itemize} @@ -1478,6 +1490,31 @@ \subsection{Implicitly Induced Getters and Setters} whose execution sets the value of \id{} to the incoming argument $x$. \LMHash{}% +\Case{Setter: Mutable variable with no declared type, with initialization} +A mutable variable declaration of the form +\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} +implicitly induces a setter with the header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. +\EndCase + +\LMHash{}% +\Case{Setter: Mutable variable with no declared type, no initialization} +A mutable variable declaration of the form +\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} +implicitly induces a setter with the header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. + +\commentary{% +It is again assumed that type inference has taken place already, +which could change \code{\VAR\,\,x;} to \code{$T$\,\,x;} +and hence take us to an earlier case.% +} +\EndCase + +\LMHash{}% +\Case{Setter: Late-final variable with declared type} A variable declaration of the form \code{\STATIC?\,\,\LATE\,\,\FINAL\,\,$T$\,\,\id;} implicitly induces a setter (\ref{setters}) with the header @@ -1496,28 +1533,10 @@ \subsection{Implicitly Induced Getters and Setters} The property that the variable is never mutated after initialization is enforced dynamically rather than statically.% } +\EndCase \LMHash{}% -A mutable variable declaration of the form -\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} -implicitly induces a setter with the header -\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, -whose execution sets the value of \id{} to the incoming argument $x$. - -\commentary{% -It is again assumed that type inference has taken place already, -which could change \code{\VAR\,\,x;} to \code{$T$\,\,x;} -and hence take us to an earlier case.% -} - -\LMHash{}% -A mutable variable declaration of the form -\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} -implicitly induces a setter with the header -\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, -whose execution sets the value of \id{} to the incoming argument $x$. - -\LMHash{}% +\Case{Setter: Late-final variable with no declared type, no initialization} A variable declaration of the form \code{\STATIC?\,\,\LATE\,\,\FINAL\,\,\id;} implicitly induces a setter with the header @@ -1528,6 +1547,7 @@ \subsection{Implicitly Induced Getters and Setters} An execution of the setter in a situation where the variable \id{} has been bound to an object will incur a dynamic error. +\EndCase \LMHash{}% The scope into which the implicit getters and setters are introduced @@ -1542,14 +1562,13 @@ \subsection{Implicitly Induced Getters and Setters} the body scope of the immediately enclosing class. \LMHash{}% -A mutable library variable introduces a setter into -the library scope of the enclosing library. -A mutable class variable introduces a static setter into -the body scope of the immediately enclosing class. -An instance variable that introduces a setter -(\commentary{it can be non-final, or late and final}) -introduces an instance setter into -the body scope of the immediately enclosing class. +A non-local variable introduces a setter if{}f it is mutable or late and final. +A library variable which introduces a setter will introduce +a library setter into the enclosing library scope. +A class variable which introduces a setter will introduce +a static setter into the body scope of the immediately enclosing class. +An instance variable that introduces a setter will introduce +an instance setter into the body scope of the immediately enclosing class. \LMHash{}% Let \id{} be a variable declared by a variable declaration @@ -1568,11 +1587,12 @@ \subsection{Implicitly Induced Getters and Setters} is also initialized in the initializer list of $k$ (\ref{initializerLists}). -A non-late static final variable \id{} does not induce a setter, +A non-late static immutable variable \id{} does not induce a setter, so unless a setter named \code{\id=} can be found by lexical lookup (\ref{lexicalLookup}), or lexical lookup yields nothing, and the location has access to \THIS, -and the enclosing class or mixin has a setter named \code{\id=}, +and the interface of the enclosing class or mixin has +a setter named \code{\id=}, it is a compile-time error to assign to \id. Similarly, assignment to a non-late final instance variable \id{} @@ -1599,10 +1619,10 @@ \subsection{Implicitly Induced Getters and Setters} \commentary{% Note that there are many situations where such a variable declaration -is a compile-time error -in which case we do not specify any of its properties, +is a compile-time error. +In this case we do not specify any of its properties, and in particular it makes no sense to say -that it has a particular initial value. +that it has a specific initial value. For example, it is an error if a final instance variable is not initialized by one of the above mechanisms.% } @@ -1631,6 +1651,7 @@ \subsection{Implicitly Induced Getters and Setters} } \LMHash{}% +\BlindDefineSymbol{\id, o}% Initialization of an instance variable \id{} with an initializing expression $e$ proceeds as follows: @@ -1697,7 +1718,7 @@ \subsection{Evaluation of Implicit Variable Getters} if the variable \code{x} has been bound to an object when its getter is invoked for the first time, $e$ will never be executed. -In other words, the initializing expression can be pre-empted.% +In other words, the initializing expression can be pre-empted by an assignment.% } \commentary{% @@ -1820,7 +1841,8 @@ \subsection{Evaluation of Implicit Variable Getters} the implicitly induced getter of \id{} is a late-initialized getter. This determines the semantics of an invocation. \commentary{% - Note that these static variables can be \emph{implicitly} late-initialized.% + Note that these static variables can be \emph{implicitly} late-initialized, + in the sense that they do not have the modifier \LATE.% } \item \emph{Constant variable.} If $d$ declares a constant variable with the initializing expression $e$, @@ -18150,10 +18172,10 @@ \subsubsection{For-in} \commentary{% It follows that it is a compile-time error -if $D$ is empty and \id{} is a final variable; -and it is a dynamic error if $e$ has a top type, +if $D$ is empty and \id{} is an immutable variable; +and it is a dynamic error if $e$ has type \DYNAMIC, but $e$ evaluates to an instance of a type -which is not a subtype of \code{Iterable}.% +which is not a subtype of \code{Iterable<\DYNAMIC>}.% } @@ -18177,7 +18199,7 @@ \subsubsection{Asynchronous For-in} % This error can occur due to implicit casts and null. It is a dynamic type error if $o$ is not an instance of a class that implements \code{Stream}. -It is a compile-time error if $D$ is empty and \id{} is a final variable. +It is a compile-time error if $D$ is empty and \id{} is an immutable variable. \LMHash{}% The stream associated with the innermost enclosing asynchronous for loop, From 30d0da7bb8aafd2a1ff992b121dc688115b68e57 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 30 Sep 2022 18:32:16 +0200 Subject: [PATCH 09/15] Improved the local variable section similarly --- specification/dartLangSpec.tex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index b856f10e77..f875180a1a 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -17651,7 +17651,7 @@ \subsection{Local Variable Declaration} The properties of being \IndexCustom{initialized}{variable!initialized}, \IndexCustom{constant}{variable!constant}, -\IndexCustom{final}{variable!final}, and +\IndexCustom{immutable}{variable!immutable}, and \IndexCustom{mutable}{variable!mutable} apply to local variables with the same definitions as for other variables (\ref{variables}). @@ -17740,10 +17740,9 @@ \subsection{Local Variable Declaration} Similarly, an expression that gives rise to an assignment to $v$ is a compile-time error unless flow analysis shows that it is guaranteed that the variable has \emph{not} been initialized.% -} -\commentary{% -It is a compile-time error to assign to a local variable +In every situation which is not covered by the previous paragraph, +it is a compile-time error to assign to a local variable which is \FINAL{} and not \LATE{} (\ref{assignment}).% } From 910f0afbab8f6d8f379bc7b73978932d8e3010ec Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 14 Jun 2023 14:13:32 +0200 Subject: [PATCH 10/15] Review response, consisting of many small changes --- specification/dartLangSpec.tex | 199 +++++++++++++++++++-------------- 1 file changed, 117 insertions(+), 82 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index f875180a1a..fd9e4eb6e2 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -747,8 +747,8 @@ \section{Notation} \commentary{% Type inference of $e_j$ and the context type used for inference of $e_j$ -are not relevant, -it is assumed that type inference has occurred already +are not relevant. +It is generally assumed that type inference has occurred already (\ref{overview}).% } @@ -1295,9 +1295,17 @@ \section{Variables} It is possible for a variable declaration to include the modifier \COVARIANT. The effect of doing this with an instance variable is described elsewhere (\ref{instanceVariables}). -It is a \Error{compile-time error} for the declaration of -a variable which is not an instance variable -to include the modifier \COVARIANT. +It is a \Error{compile-time error} for the declaration of a variable +which is not an instance variable to include the modifier \COVARIANT. + +\commentary{% +A formal parameter declaration induces a local variable into a scope, +but formal parameter declarations are not variable declarations +and do not give rise to the above error. +The effect of having the modifier \COVARIANT{} on a formal parameter +is described elsewhere +(\ref{covariantParameters}).% +} \LMHash{}% In a variable declaration of one of the forms @@ -1306,9 +1314,9 @@ \section{Variables} \code{$N$\,\,\id{} = $e$;} where $N$ is derived from \syntax{ } and \id{} is an identifier, -we say that \id{} is the \Index{declaring occurrence} of the identifier. +we say that \id{} is a \Index{declaring occurrence} of the identifier. For every identifier which is not a declaring occurrence, -we say that it is an \Index{referencing occurrence}. +we say that it is a \Index{referencing occurrence}. We also abbreviate that to say that an identifier is a \Index{declaring identifier} respectively an \Index{referencing identifier}. @@ -1345,11 +1353,15 @@ \section{Variables} It is a \Error{compile-time error} if a library variable declaration has the modifier \STATIC. +%% TODO(eernst): Get rid of the phrase 'static variable' meaning a non-local +%% variable which isn't an instance variable. Then use 'static variable +%% declaration' to mean "a variable declaration that includes the modifier +%% \STATIC." \LMHash{}% A \IndexCustom{class variable}{variable!class} is a variable whose declaration is -immediately nested inside a class declaration and -includes the modifier \STATIC. +immediately nested inside a \CLASS, \MIXIN, \ENUM, or \EXTENSION{} declaration +and includes the modifier \STATIC. \LMHash{}% A \IndexCustom{static variable}{variable!static} @@ -1394,9 +1406,12 @@ \section{Variables} \LMHash{}% An \IndexCustom{immutable variable}{variable!immutable} -is a variable whose binding is fixed upon initialization; -an immutable variable \id{} will always refer to the same object -after \id{} has been initialized. +is a variable which cannot be bound to a different object +once it has been bound to an object. +\commentary{% +Hence, an immutable variable \id{} will always refer to the same object +after \id{} has been initialized.% +} A variable is immutable if{}f its declaration includes the modifier \FINAL{} or the modifier \CONST. A \IndexCustom{mutable variable}{variable!mutable} @@ -1464,14 +1479,15 @@ \subsection{Implicitly Induced Getters and Setters} \commentary{% Type inference is assumed to have taken place already -(\ref{typeInference}). +(\ref{overview}). For example, an instance variable declaration of the form \code{\VAR\,\,x;} could have been transformed into \code{$T$\,\,x;} based on member signatures named \code{x} in superinterfaces of the enclosing class, and \code{\VAR\,x\,\,=\,\,$e$;} could have been transformed into \code{$T$\,x\,\,=\,\,$e$;} -where $T$ is the static type of $e$.% +where $T$ is the static type of $e$. +In that case, the type is $T$ rather than \DYNAMIC.% } \EndCase @@ -1496,6 +1512,11 @@ \subsection{Implicitly Induced Getters and Setters} implicitly induces a setter with the header \code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, whose execution sets the value of \id{} to the incoming argument $x$. + +\commentary{% +Type inference could have provided a type different from \DYNAMIC{} +(\ref{overview}).% +} \EndCase \LMHash{}% @@ -1507,9 +1528,11 @@ \subsection{Implicitly Induced Getters and Setters} whose execution sets the value of \id{} to the incoming argument $x$. \commentary{% -It is again assumed that type inference has taken place already, -which could change \code{\VAR\,\,x;} to \code{$T$\,\,x;} -and hence take us to an earlier case.% +Type inference has not yet been specified in this document +(\ref{overview}). +Note that type inference could change, e.g., +\code{\VAR\,\,x;} to \code{$T$\,\,x;}, +which would take us to an earlier case.% } \EndCase @@ -1525,14 +1548,6 @@ \subsection{Implicitly Induced Getters and Setters} If this setter is executed in a situation where the variable \id{} has been bound to an object, a dynamic error occurs. - -\commentary{% -A late final variable declaration with no initializer is permitted. -It introduces a variable which may be assigned to -so long as the variable is not known to be definitely assigned. -The property that the variable is never mutated after initialization -is enforced dynamically rather than statically.% -} \EndCase \LMHash{}% @@ -1557,18 +1572,27 @@ \subsection{Implicitly Induced Getters and Setters} A library variable introduces a getter into the library scope of the enclosing library. A class variable introduces a static getter into -the body scope of the immediately enclosing class. +%% TODO(eernst): Come enhanced enums, add enum to this list. +the body scope of the immediately enclosing class, mixin, or extension. An instance variable introduces an instance getter into -the body scope of the immediately enclosing class. +%% TODO(eernst): Come enhanced enums, add enum to this list. +the body scope of the immediately enclosing class or mixin +(\commentary{an extension cannot declare instance variables}). \LMHash{}% -A non-local variable introduces a setter if{}f it is mutable or late and final. +A non-local variable introduces a setter if{}f it is mutable, +or it is late and final and does not have an initializing expression. A library variable which introduces a setter will introduce a library setter into the enclosing library scope. -A class variable which introduces a setter will introduce -a static setter into the body scope of the immediately enclosing class. +A class variable which introduces a setter will introduce +a static setter into the body scope of +%% TODO(eernst): Come enhanced enums, add enum to this list. +the immediately enclosing class, mixin, or extension. An instance variable that introduces a setter will introduce -an instance setter into the body scope of the immediately enclosing class. +an instance setter into the body scope of +%% TODO(eernst): Come enhanced enums, add enum to this list. +the immediately enclosing class or mixin +(\commentary{an extension cannot declare instance variables}). \LMHash{}% Let \id{} be a variable declared by a variable declaration @@ -1587,23 +1611,20 @@ \subsection{Implicitly Induced Getters and Setters} is also initialized in the initializer list of $k$ (\ref{initializerLists}). -A non-late static immutable variable \id{} does not induce a setter, -so unless a setter named \code{\id=} can be found by lexical lookup -(\ref{lexicalLookup}), -or lexical lookup yields nothing, and the location has access to \THIS, -and the interface of the enclosing class or mixin has -a setter named \code{\id=}, -it is a compile-time error to assign to \id. +A non-late static immutable variable declaration $D$ named \id{} +does not induce a setter. +However, an assignment to \id{} at a location where $D$ is in scope +is not necessarily a compile-time error. +For example, a setter named \code{\id=} could be found by lexical lookup +(\ref{lexicalLookup}). -Similarly, assignment to a non-late final instance variable \id{} -is a compile-time error, -unless a setter named \code{\id=} can be found as above, -or the receiver has type \DYNAMIC. -\id{} can be initialized in its declaration or in initializer lists, -but initialization and assignment is not the same thing. -When the receiver has type \DYNAMIC{} -such an assignment is not a compile-time error, -but if there is no such setter it will cause a dynamic error.% +Similarly, a non-late final instance variable \id{} does not induce a setter, +but an assignment could be an invocation of +a setter which is provided in some other way. +For example, it could be that lexical lookup yields nothing, +and the location of the assignment has access to \THIS, +and the interface of an enclosing class has a setter named \code{\id=} +(in this case both the getter and setter are inherited).% } \LMHash{}% @@ -1619,12 +1640,8 @@ \subsection{Implicitly Induced Getters and Setters} \commentary{% Note that there are many situations where such a variable declaration -is a compile-time error. -In this case we do not specify any of its properties, -and in particular it makes no sense to say -that it has a specific initial value. -For example, it is an error if a final instance variable -is not initialized by one of the above mechanisms.% +is a compile-time error, +in which case the initial value is of course irrelevant.% } \LMHash{}% @@ -1695,18 +1712,22 @@ \subsection{Evaluation of Implicit Variable Getters} is a getter $g$ which is implicitly induced by a non-local variable $v$ that has an initializing expression $e$. \commentary{% -Note that only \emph{some} non-local variables with an initializing expression -induce a late-initialized getter, -and others induce other kinds of getters, as described below.% +It is described below which declarations induce a late-initialized getter.% } An invocation of $g$ proceeds as follows: + +\LMHash{}% If the variable $v$ has not been bound to an object then -$e$ is evaluated to an object $o$, -$v$ is bound to $o$, +$e$ is evaluated to an object $o$. +If $v$ has now been bound to an object, and $v$ is immutable, +a dynamic error occurs. % Implementations throw a 'LateInitializationError'. +Otherwise, $v$ is bound to $o$, and the evaluation of $g$ completes returning $o$. If the evaluation of $e$ throws then the invocation of $g$ completes throwing the same object and stack trace, and no binding of $v$ to any object occurs. + +\LMHash{}% An invocation of $g$ in a situation where $v$ has been bound to an object $o'$ completes immediately, returning $o'$. @@ -1793,9 +1814,10 @@ \subsection{Evaluation of Implicit Variable Getters} the object that \id{} is bound to. \commentary{% -Any situation where \id{} is unbound when this getter is evaluated -is a compile-time error, -so there is no need to specify a behavior for that situation.% +It is not possible to invoke an instance getter on an object +before the object has been initialized. +Hence, a non-late instance variable is always bound +when the instance getter is invoked.% } \EndCase @@ -1857,7 +1879,7 @@ \subsection{Evaluation of Implicit Variable Getters} and does not have the modifier \LATE, an invocation of the implicitly induced getter of \id{} evaluates to the object that \id{} is bound to. - + \commentary{% The variable is always bound to an object in this case. This may be the null object, @@ -3951,18 +3973,21 @@ \subsubsection{Generative Constructors} A term of the form \code{\THIS.\id} is contained in $p$, and \id{} is the \NoIndex{name} of $p$. It is a compile-time error if \id{} is not also the name of +%% TODO(eernst): Come enhanced enums, add 'or enum'. an instance variable of the immediately enclosing class. \commentary{% Note that it is a compile-time error for an initializing formal to occur in any function which is not a non-redirecting generative constructor (\ref{requiredFormals}), +%% TODO(eernst): Come enhanced enums, add 'or enum'. so there is always an enclosing class.% } \LMHash{}% Assume that $p$ is a declaration of an initializing formal parameter named \id. Let $T_{id}$ be the type of the instance variable named \id{} in +%% TODO(eernst): Come enhanced enums, add 'or enum'. the immediately enclosing class. If $p$ has a type annotation $T$ then the declared type of $p$ is $T$. Otherwise, the declared type of $p$ is $T_{id}$. @@ -4248,6 +4273,7 @@ \subsubsection{Generative Constructors} \LMHash{}% Let \DefineSymbol{f} be a final instance variable declared in +%% TODO(eernst): Come enhanced enums, add 'or enum'. the immediately enclosing class. A compile-time error occurs unless $f$ is initialized by one of the following means: @@ -4281,6 +4307,7 @@ \subsubsection{Generative Constructors} Execution of a generative constructor $k$ of type $T$ to initialize a fresh instance $i$ is always done with respect to a set of bindings for its formal parameters +%% TODO(eernst): Come enhanced enums, add 'or enum'. and the type parameters of the immediately enclosing class bound to a set of actual type arguments of $T$, \DefineSymbol{\List{t}{1}{m}}. @@ -4313,6 +4340,7 @@ \subsubsection{Generative Constructors} the formal parameters of $g$ to the corresponding objects in the actual argument list $a$, with \THIS{} bound to $i$, +%% TODO(eernst): Come enhanced enums, add 'or enum'. and the type parameters of the immediately enclosing class bound to \List{t}{1}{m}. @@ -4321,6 +4349,7 @@ \subsubsection{Generative Constructors} Execution then proceeds as follows: \LMHash{}% +%% TODO(eernst): Come enhanced enums, add 'or enum'. The instance variable declarations of the immediately enclosing class are visited in the order they appear in the program text. For each such declaration $d$, if $d$ has the form @@ -4343,7 +4372,9 @@ \subsubsection{Generative Constructors} } \LMHash{}% -Then if any instance variable of $i$ declared by the immediately enclosing class +Then if any instance variable of $i$ declared +%% TODO(eernst): Come enhanced enums, add 'or enum'. +by the immediately enclosing class is not yet bound to an object, all such variables are initialized with the null object (\ref{null}). @@ -4447,6 +4478,8 @@ \subsubsection{Factories} \LMHash{}% It is a compile-time error if $M$ is not the name of +%% TODO(eernst): Come enhanced enums, add 'or enum'. +%% TODO(eernst): Come Dart 3.0, add 'mixin'. the immediately enclosing class. \LMHash{}% @@ -4621,6 +4654,8 @@ \subsubsection{Factories} In the case where the two classes are non-generic this is just a subtype check on the function types of the two constructors. In general, this implies that the resulting object conforms to +%% TODO(eernst): Come enhanced enums, add 'or enum'. +%% TODO(eernst): Come Dart 3.0, add 'mixin'. the interface of the immediately enclosing class of $k$.% } @@ -11907,17 +11942,24 @@ \subsection{This} \end{grammar} \LMHash{}% -The static type of \THIS{} is the interface of the immediately enclosing class. +The static type of \THIS{} is the interface of the +%% TODO(eernst): Come enhanced enums, add 'or enum'. +immediately enclosing class or mixin, if any. +The static type of \THIS{} is +the \ON{} type of the enclosing extension, if any +(\ref{extensions}). \commentary{% -We do not support self-types at this point.% +If none of those declarations exist, +an occurrence of \THIS{} is a compile-time error +(\ref{classes}).% } \LMHash{}% It is a compile-time error if \THIS{} appears, implicitly or explicitly, in a top-level function or variable initializer, in a factory constructor, or in a static method or variable initializer, -or in the initializer of an instance variable. +or in the initializing expression of a non-late instance variable. \subsection{Instance Creation} @@ -17860,6 +17902,15 @@ \subsection{Local Variable Declaration} of $v$. Otherwise, the variable $v$ is bound to $o$. +\commentary{% +Note that $e$ could have been transformed due to implicit coercions. +For example, \code{myFunction} could be transformed into +\code{myFunction} due to generic function instantiation +(\ref{genericFunctionInstantiation}). +Such transformations are assumed to have taken place already +in the declarations above.% +} + \LMHash{}% Let $D$ be a \LATE{} and \FINAL{} local variable declaration that declares a variable $v$. @@ -17871,22 +17922,6 @@ \subsection{Local Variable Declaration} then a dynamic error occurs (\commentary{it does not matter whether $o$ is the same object as $o'$}). -\commentary{% -Note that this includes the implicit initializing writes induced by -evaluating the variable. -Hence, the following program encounters a dynamic error -when it evaluates \code{x}, -just before it would call \code{print}.% -} - -\begin{dartCode} -\VOID\ main() \{ - int i = 0; - \LATE\ \FINAL\ int x = i++ == 0 ? x + 1 : 0; - print(x); -\} -\end{dartCode} - \subsection{Local Function Declaration} \LMLabel{localFunctionDeclaration} From 3c47ea0a29e80cf553e723d96cffe8a0dacb606a Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 14 Jun 2023 14:52:35 +0200 Subject: [PATCH 11/15] Improved comment --- specification/dartLangSpec.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index fd9e4eb6e2..c08a562ce9 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -18206,8 +18206,8 @@ \subsubsection{For-in} \commentary{% It follows that it is a compile-time error -if $D$ is empty and \id{} is an immutable variable; -and it is a dynamic error if $e$ has type \DYNAMIC, +if $D$ is empty and \id{} is an immutable variable. +Also, it is a dynamic error if $e$ has type \DYNAMIC, but $e$ evaluates to an instance of a type which is not a subtype of \code{Iterable<\DYNAMIC>}.% } From 77717eb237467c9dfc9cc8ccf19b6e701e4ee0db Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 18 Jul 2023 18:06:26 +0200 Subject: [PATCH 12/15] Review response --- specification/dartLangSpec.tex | 186 ++++++++++++++++----------------- 1 file changed, 91 insertions(+), 95 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index c08a562ce9..c8dd85f851 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -41,6 +41,14 @@ % version of the language which will actually be specified by the next stable % release of this document. % +% Jul 2023 +% - Land the null-safety updates for sections about variables. +% - Change terminology: A 'static variable' is now a variable whose declaration +% includes `static` (which used to be called a 'class variable'); the old +% meaning of 'static variable' is now called a 'statically allocated +% variable'. This avoids the confusion that came up just about every single +% time the phrase 'static variable' came up in a discussion. +% % Mar 2023 % - Clarify how line breaks are handled in a multi-line string literal. Rename % the lexical token NEWLINE to LINE\_BREAK (clarifying that it is not `\n`). @@ -1353,24 +1361,20 @@ \section{Variables} It is a \Error{compile-time error} if a library variable declaration has the modifier \STATIC. -%% TODO(eernst): Get rid of the phrase 'static variable' meaning a non-local -%% variable which isn't an instance variable. Then use 'static variable -%% declaration' to mean "a variable declaration that includes the modifier -%% \STATIC." \LMHash{}% -A \IndexCustom{class variable}{variable!class} +A \IndexCustom{static variable}{variable!static} is a variable whose declaration is immediately nested inside a \CLASS, \MIXIN, \ENUM, or \EXTENSION{} declaration and includes the modifier \STATIC. \LMHash{}% -A \IndexCustom{static variable}{variable!static} +A \IndexCustom{statically allocated variable}{variable!statically allocated} is a variable that is not associated with a particular instance, but rather with an entire library or class. -Static variables include library variables and class variables. +Statically allocated variables include library variables and static variables. \LMHash{}% -A \Error{compile-time error} occurs if a static variable has a +A \Error{compile-time error} occurs if a statically allocated variable has no initializing expression and a type which is not nullable (\ref{typeNullability}), unless the variable declaration has @@ -1378,7 +1382,7 @@ \section{Variables} \LMHash{}% A \IndexCustom{non-local variable}{variable!non-local} -is a library variable, a class variable, or an instance variable. +is a library variable, a static variable, or an instance variable. \commentary{% That is, any kind of variable which is not a local variable.% } @@ -1394,14 +1398,19 @@ \section{Variables} An initializing expression $e$ of a constant variable declaration occurs in a constant context (\ref{constantContexts}). -This means that \CONST{} modifiers in $e$ need not be specified explicitly. +This means that \CONST{} modifiers in $e$ need not be specified explicitly.% +} +\rationale{% It is grammatically impossible for a constant variable declaration to have the modifier \LATE. However, even if it had been grammatically possible, a \LATE{} constant variable would still have to be a compile-time error, because being a compile-time constant is inherently incompatible -with being computed late.% +with being computed late. + +Similarly, an instance variable cannot be constant +(\ref{instanceVariables}).% } \LMHash{}% @@ -1426,6 +1435,10 @@ \subsection{Implicitly Induced Getters and Setters} %% (for instance `var x;` or `var x = e;`), and then we can replace all rules %% about such cases by commentary saying that they may exist in the input, %% but they are gone after type inference. +%% +%% At this time we rely on the assumption that type inference has already +%% occurred, which means that we can refer to the declared type of a variable +%% without mentioning type inference. \LMHash{}% The following rules on implicitly induced getters and setters @@ -1470,25 +1483,15 @@ \subsection{Implicitly Induced Getters and Setters} \end{itemize} \noindent -implicitly induces a getter with the header -\code{\DYNAMIC\,\,\GET\,\,\id}, -whose invocation evaluates as described below +implicitly induces a getter with the header that +contains \STATIC{} if{}f the declaration contains \STATIC{} and is followed by +\code{$T$\,\,\GET\,\,\id}, +where $T$ is obtained from type inference +in the case where $e$ exists, +and $T$ is \DYNAMIC{} otherwise. +The invocation of this getter evaluates as described below (\ref{evaluationOfImplicitVariableGetters}). -In these cases, the declared type of \id{} is \DYNAMIC{} -(\ref{typeDynamic}). - -\commentary{% -Type inference is assumed to have taken place already -(\ref{overview}). -For example, an instance variable declaration of the form -\code{\VAR\,\,x;} could have been transformed into -\code{$T$\,\,x;} based on member signatures named \code{x} in superinterfaces -of the enclosing class, and -\code{\VAR\,x\,\,=\,\,$e$;} could have been transformed into -\code{$T$\,x\,\,=\,\,$e$;} -where $T$ is the static type of $e$. -In that case, the type is $T$ rather than \DYNAMIC.% -} +In these cases, the declared type of \id{} is $T$. \EndCase \LMHash{}% @@ -1571,12 +1574,12 @@ \subsection{Implicitly Induced Getters and Setters} \LMHash{}% A library variable introduces a getter into the library scope of the enclosing library. -A class variable introduces a static getter into -%% TODO(eernst): Come enhanced enums, add enum to this list. -the body scope of the immediately enclosing class, mixin, or extension. +A static variable introduces a static getter into +the body scope of the immediately enclosing +class, mixin, enum, or extension declaration. An instance variable introduces an instance getter into -%% TODO(eernst): Come enhanced enums, add enum to this list. -the body scope of the immediately enclosing class or mixin +the body scope of the immediately enclosing +class, mixin, or enum declaration (\commentary{an extension cannot declare instance variables}). \LMHash{}% @@ -1584,14 +1587,12 @@ \subsection{Implicitly Induced Getters and Setters} or it is late and final and does not have an initializing expression. A library variable which introduces a setter will introduce a library setter into the enclosing library scope. -A class variable which introduces a setter will introduce -a static setter into the body scope of -%% TODO(eernst): Come enhanced enums, add enum to this list. -the immediately enclosing class, mixin, or extension. +A static variable which introduces a setter will introduce +a static setter into the body scope of the immediately enclosing +class, mixin, enum, or extension declaration. An instance variable that introduces a setter will introduce -an instance setter into the body scope of -%% TODO(eernst): Come enhanced enums, add enum to this list. -the immediately enclosing class or mixin +an instance setter into the body scope of the immediately enclosing +class, mixin, or enum declaration (\commentary{an extension cannot declare instance variables}). \LMHash{}% @@ -1648,8 +1649,10 @@ \subsection{Implicitly Induced Getters and Setters} Otherwise, variable initialization proceeds as follows: \LMHash{}% -A static variable declaration -(\commentary{that is, a declaration of a library variable or a class variable}) +A declaration of a statically allocated variable +(\commentary{% +that is, a declaration of a library variable or a static variable% +}) with an initializing expression is initialized lazily (\ref{evaluationOfImplicitVariableGetters}). @@ -1725,7 +1728,7 @@ \subsection{Evaluation of Implicit Variable Getters} and the evaluation of $g$ completes returning $o$. If the evaluation of $e$ throws then the invocation of $g$ completes throwing the same object and stack trace, -and no binding of $v$ to any object occurs. +and does not change the binding of $v$. \LMHash{}% An invocation of $g$ in a situation where $v$ has been bound to an object $o'$ @@ -1852,9 +1855,9 @@ \subsection{Evaluation of Implicit Variable Getters} \EndCase \LMHash{}% -\Case{Static variable} -If $d$ declares a static variable -(\commentary{that is, a library variable or a class variable}), +\Case{Statically allocated variable} +If $d$ declares a statically allocated variable +(\commentary{that is, a library variable or a static variable}), the implicitly induced getter of \id{} executes as follows: \begin{itemize} @@ -1863,8 +1866,9 @@ \subsection{Evaluation of Implicit Variable Getters} the implicitly induced getter of \id{} is a late-initialized getter. This determines the semantics of an invocation. \commentary{% - Note that these static variables can be \emph{implicitly} late-initialized, - in the sense that they do not have the modifier \LATE.% + Note that these statically allocated variables can be \emph{implicitly} + late-initialized, in the sense that they do not have + the modifier \LATE.% } \item \emph{Constant variable.} If $d$ declares a constant variable with the initializing expression $e$, @@ -2803,7 +2807,7 @@ \section{Classes} The \IndexCustom{instance members}{members!instance} of a class are its instance methods, getters, setters and instance variables. The \IndexCustom{static members}{members!static} of a class -are its static methods, getters, setters and class variables. +are its static methods, getters, setters, and variables. The \IndexCustom{members}{members} of a class are its static and instance members. @@ -3849,7 +3853,7 @@ \subsection{Instance Variables} as its getter would be subject to overriding. Given that the value does not depend on the instance, -it is better to use a class variable. +it is better to use a static variable. An instance getter for it can always be defined manually if desired.% } @@ -3973,22 +3977,19 @@ \subsubsection{Generative Constructors} A term of the form \code{\THIS.\id} is contained in $p$, and \id{} is the \NoIndex{name} of $p$. It is a compile-time error if \id{} is not also the name of -%% TODO(eernst): Come enhanced enums, add 'or enum'. -an instance variable of the immediately enclosing class. +an instance variable of the immediately enclosing class or enum. \commentary{% Note that it is a compile-time error for an initializing formal to occur in any function which is not a non-redirecting generative constructor (\ref{requiredFormals}), -%% TODO(eernst): Come enhanced enums, add 'or enum'. -so there is always an enclosing class.% +so there is always an enclosing class or enum.% } \LMHash{}% Assume that $p$ is a declaration of an initializing formal parameter named \id. Let $T_{id}$ be the type of the instance variable named \id{} in -%% TODO(eernst): Come enhanced enums, add 'or enum'. -the immediately enclosing class. +the immediately enclosing class or enum. If $p$ has a type annotation $T$ then the declared type of $p$ is $T$. Otherwise, the declared type of $p$ is $T_{id}$. It is a compile-time error if the declared type of $p$ @@ -4273,8 +4274,7 @@ \subsubsection{Generative Constructors} \LMHash{}% Let \DefineSymbol{f} be a final instance variable declared in -%% TODO(eernst): Come enhanced enums, add 'or enum'. -the immediately enclosing class. +the immediately enclosing class or enum. A compile-time error occurs unless $f$ is initialized by one of the following means: \begin{itemize} @@ -4307,8 +4307,7 @@ \subsubsection{Generative Constructors} Execution of a generative constructor $k$ of type $T$ to initialize a fresh instance $i$ is always done with respect to a set of bindings for its formal parameters -%% TODO(eernst): Come enhanced enums, add 'or enum'. -and the type parameters of the immediately enclosing class bound to +and the type parameters of the immediately enclosing class or enum bound to a set of actual type arguments of $T$, \DefineSymbol{\List{t}{1}{m}}. \commentary{% @@ -4340,8 +4339,7 @@ \subsubsection{Generative Constructors} the formal parameters of $g$ to the corresponding objects in the actual argument list $a$, with \THIS{} bound to $i$, -%% TODO(eernst): Come enhanced enums, add 'or enum'. -and the type parameters of the immediately enclosing class bound to +and the type parameters of the immediately enclosing class or enum bound to \List{t}{1}{m}. \LMHash{}% @@ -4349,8 +4347,7 @@ \subsubsection{Generative Constructors} Execution then proceeds as follows: \LMHash{}% -%% TODO(eernst): Come enhanced enums, add 'or enum'. -The instance variable declarations of the immediately enclosing class +The instance variable declarations of the immediately enclosing class or enum are visited in the order they appear in the program text. For each such declaration $d$, if $d$ has the form \code{\synt{finalConstVarOrType} $v$ = $e$; } @@ -4373,8 +4370,7 @@ \subsubsection{Generative Constructors} \LMHash{}% Then if any instance variable of $i$ declared -%% TODO(eernst): Come enhanced enums, add 'or enum'. -by the immediately enclosing class +by the immediately enclosing class or enum is not yet bound to an object, all such variables are initialized with the null object (\ref{null}). @@ -4478,9 +4474,8 @@ \subsubsection{Factories} \LMHash{}% It is a compile-time error if $M$ is not the name of -%% TODO(eernst): Come enhanced enums, add 'or enum'. %% TODO(eernst): Come Dart 3.0, add 'mixin'. -the immediately enclosing class. +the immediately enclosing class or enum. \LMHash{}% % This error can occur due to an implicit cast. @@ -4654,9 +4649,8 @@ \subsubsection{Factories} In the case where the two classes are non-generic this is just a subtype check on the function types of the two constructors. In general, this implies that the resulting object conforms to -%% TODO(eernst): Come enhanced enums, add 'or enum'. %% TODO(eernst): Come Dart 3.0, add 'mixin'. -the interface of the immediately enclosing class of $k$.% +the interface of the class or enum that immediately encloses $k$.% } \LMHash{}% @@ -4965,11 +4959,13 @@ \subsubsection{Inheritance and Overriding} \item There is only one namespace for getters, setters, methods and constructors (\ref{scoping}). - An instance or static variable $f$ introduces a getter $f$, - and a mutable instance or static variable $f$ also introduces a setter + An instance or statically allocated variable $f$ introduces a getter $f$, + and a mutable instance or statically allocated variable $f$ + also introduces a setter \code{$f$=} (\ref{instanceVariables}, \ref{variables}). When we speak of members here, we mean - accessible instance or static variables, getters, setters, and methods + accessible instance or statically allocated variables, + getters, setters, and methods (\ref{classes}). \item You cannot have two members with the same name in the same class---be they declared or inherited (\ref{scoping}, \ref{classes}). @@ -5113,7 +5109,7 @@ \subsection{Class Member Conflicts} \LMLabel{classMemberConflicts} \LMHash{}% -Some pairs of class, mixin, and extension member declarations +Some pairs of class, mixin, enum, and extension member declarations cannot coexist, even though they do not both introduce the same name into the same scope. This section specifies these errors. @@ -11943,8 +11939,7 @@ \subsection{This} \LMHash{}% The static type of \THIS{} is the interface of the -%% TODO(eernst): Come enhanced enums, add 'or enum'. -immediately enclosing class or mixin, if any. +immediately enclosing class, enum, or mixin, if any. The static type of \THIS{} is the \ON{} type of the enclosing extension, if any (\ref{extensions}). @@ -13124,7 +13119,7 @@ \subsubsection{Unqualified Invocation} \begin{itemize} \item When $D$ is a type declaration, that is, - a declaration of a class, mixin, type alias, or type parameter, + a declaration of a class, mixin, enum, type alias, or type parameter, the following applies: If $D$ is a declaration of a class $C$ that has a constructor named $C$ @@ -13151,7 +13146,7 @@ \subsubsection{Unqualified Invocation} \item Otherwise, if $D$ is a static method or getter - (\commentary{which may be implicitly induced by a class variable}) + (\commentary{which may be implicitly induced by a static variable}) in the enclosing class or mixin $C$, $i$ is treated as (\ref{notation}) @@ -14233,9 +14228,9 @@ \subsubsection{Ordinary Invocation} \rationale{% The reason for this rule is that member access on a type literal is reserved for invocation of static members. -Invocation of a static member of a class, mixin, or extension +Invocation of a static member of a class, mixin, enum, or extension uses said entity as a \emph{namespace}, -not as an actual class, mixin, or extension. +not as an actual class, mixin, enum, or extension. In particular, the syntactic receiver is not evaluated to an object---that would not even be possible for an extension.% } @@ -16695,7 +16690,7 @@ \subsection{Postfix Expressions} where $C$ is a type literal and \op{} is either \lit{++} or \lit{-{}-}. A compile-time error occurs unless \code{$C$.$v$} denotes a static getter and there is an associated static setter \code{$v$=} -(\commentary{possibly implicitly induced by a class variable}). +(\commentary{possibly implicitly induced by a static variable}). Let $T$ be the return type of said getter. A compile-time error occurs if $T$ is not \DYNAMIC{} and $T$ does not have an operator \lit{+} (when \op{} is \lit{++}) @@ -17089,7 +17084,7 @@ \subsection{Lexical Lookup} of a class or a mixin. It is a compile-time error if $\ell$ occurs inside a static method, static getter, or static setter, - or inside a class variable initializer. + or inside a static variable initializer. % NB: There is _no_ error when it occurs in an instance variable initializer, % which means that it is allowed "to access `this`" in that particular case. % This may seem inconsistent, but it should not be harmful. @@ -17106,7 +17101,7 @@ \subsection{Lexical Lookup} % - an import with prefix \id; % - a class or type alias; % whose name must be \id, no need to say that.. % - a library variable, getter, or setter; - % - a static method/getter/setter of a class, mixin, or extension; + % - a static method/getter/setter of a class, mixin, enum, or extension; % - an instance method of an extension; % - a local variable (\commentary{which may be a formal parameter}); % - a local function. @@ -17200,8 +17195,9 @@ \subsection{Identifier Reference} \LMHash{}% A \Index{built-in identifier} is one of the identifiers produced by the production \synt{BUILT\_IN\_IDENTIFIER}. -It is a compile-time error if a built-in identifier is used as -the declared name of a prefix, class, mixin, type parameter, or type alias. +It is a compile-time error if a built-in identifier +is used as the declared name of +a prefix, class, mixin, enum, type parameter, or type alias. It is a compile-time error to use a built-in identifier other than \DYNAMIC{} or \FUNCTION{} as an identifier in a type annotation or a type parameter bound. @@ -17232,7 +17228,7 @@ \subsection{Identifier Reference} A \Index{qualified name} is two or three identifiers separated by \lit{.}. All but the last one must be a \synt{typeIdentifier}. It is used to denote a declaration which is imported with a prefix, -or a \STATIC{} declaration in a class, mixin, or extension, or both. +or a \STATIC{} declaration in a class, mixin, enum, or extension, or both. \LMHash{}% The static type of an identifier expression $e$ which is an identifier \id{} @@ -17247,7 +17243,7 @@ \subsection{Identifier Reference} \begin{itemize} \item - If $D$ declares a class, mixin, type alias, an enumerated type, + If $D$ declares a class, mixin, enum, type alias, an enumerated type, or a type parameter, the static type of $e$ is \code{Type}. \item @@ -17267,7 +17263,7 @@ \subsection{Identifier Reference} } \item If $D$ is the declaration of a static getter - (\commentary{which may be implicitly induced by a class variable}) + (\commentary{which may be implicitly induced by a static variable}) and $D$ occurs in the class $C$, the static type of $e$ is the return type of the getter \code{$C$.\id}. @@ -17350,7 +17346,7 @@ \subsection{Identifier Reference} \begin{itemize} \item - If $D$ is a class, mixin, or type alias, + If $D$ is a class, mixin, enum, or type alias, the value of $e$ is an object implementing the class \code{Type} which reifies the corresponding type. \item @@ -17396,7 +17392,7 @@ \subsection{Identifier Reference} \commentary{% Note that $D$ cannot be the declaration of -a class variable, static getter or static setter declared in a class $C$, +a static variable, static getter or static setter declared in a class $C$, because in that case $e$ is treated as (\ref{notation}) the property extraction @@ -17486,7 +17482,7 @@ \subsection{Type Test} but not reject any code now error-free. The rule only applies to locals and parameters, -as instance and static variables could be modified +as instance variables and statically allocated variables could be modified via side-effecting functions or methods that are not accessible to a local analysis. @@ -20007,7 +20003,7 @@ \subsubsection{Semantics of Imports} % This error can occur because being-loaded is a dynamic property. Calling the setter results in a dynamic error. \item - For every class, mixin and type alias declaration named \id{} in + For every class, mixin, enum, and type alias declaration named \id{} in \NamespaceName{\metavar{import},i}, a corresponding getter named \id{} with return type \code{Type}. % This error can occur because being-loaded is a dynamic property. @@ -20093,7 +20089,7 @@ \subsubsection{Semantics of Imports} a binding from $n$ to said function, getter, or setter. \item For every name \id{} in \NamespaceName{\metavar{import}, i} - that is bound to a class, mixin, or type alias declaration + that is bound to a class, mixin, enum, or type alias declaration introducing a type $T$, a binding from \id{} to the compiled representation of $T$. \end{itemize} @@ -20964,7 +20960,7 @@ \subsection{Dynamic Type System} \LMHash{}% An expression is a \emph{type literal} if it is an identifier, or a qualified identifier, -which denotes a class, mixin or type alias declaration, or it is +which denotes a class, mixin, enum, or type alias declaration, or it is an identifier denoting a type parameter of a generic class or function. It is a \emph{constant type literal} if it does not denote a type parameter, and it is not qualified by a deferred prefix. From 8544c41c370586d4a7c528a3fc24e9145f21316c Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 19 Jul 2023 12:34:20 +0200 Subject: [PATCH 13/15] Now using non-local variable where possible, and "static or library variable" where we used to have "statically allocated variable", and "static variable" before that again --- specification/dartLangSpec.tex | 36 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index c8dd85f851..0611bb3139 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -45,9 +45,11 @@ % - Land the null-safety updates for sections about variables. % - Change terminology: A 'static variable' is now a variable whose declaration % includes `static` (which used to be called a 'class variable'); the old -% meaning of 'static variable' is now called a 'statically allocated -% variable'. This avoids the confusion that came up just about every single -% time the phrase 'static variable' came up in a discussion. +% meaning of 'static variable' is now never used (we spell out every time +% that it is a 'library variable or a static variable', where the latter is +% the new meaning of that phrase). This avoids the confusion that came up +% just about every single time the phrase 'static variable' came up in a +% discussion. % % Mar 2023 % - Clarify how line breaks are handled in a multi-line string literal. Rename @@ -1368,13 +1370,7 @@ \section{Variables} and includes the modifier \STATIC. \LMHash{}% -A \IndexCustom{statically allocated variable}{variable!statically allocated} -is a variable that is not associated with a particular instance, -but rather with an entire library or class. -Statically allocated variables include library variables and static variables. - -\LMHash{}% -A \Error{compile-time error} occurs if a statically allocated variable has +A \Error{compile-time error} occurs if a static or library variable has no initializing expression and a type which is not nullable (\ref{typeNullability}), unless the variable declaration has @@ -1649,10 +1645,7 @@ \subsection{Implicitly Induced Getters and Setters} Otherwise, variable initialization proceeds as follows: \LMHash{}% -A declaration of a statically allocated variable -(\commentary{% -that is, a declaration of a library variable or a static variable% -}) +A declaration of a static or library variable with an initializing expression is initialized lazily (\ref{evaluationOfImplicitVariableGetters}). @@ -1855,9 +1848,8 @@ \subsection{Evaluation of Implicit Variable Getters} \EndCase \LMHash{}% -\Case{Statically allocated variable} -If $d$ declares a statically allocated variable -(\commentary{that is, a library variable or a static variable}), +\Case{Static or library variable} +If $d$ declares a static or library variable, the implicitly induced getter of \id{} executes as follows: \begin{itemize} @@ -1866,7 +1858,7 @@ \subsection{Evaluation of Implicit Variable Getters} the implicitly induced getter of \id{} is a late-initialized getter. This determines the semantics of an invocation. \commentary{% - Note that these statically allocated variables can be \emph{implicitly} + Note that these static or library variables can be \emph{implicitly} late-initialized, in the sense that they do not have the modifier \LATE.% } @@ -4959,12 +4951,12 @@ \subsubsection{Inheritance and Overriding} \item There is only one namespace for getters, setters, methods and constructors (\ref{scoping}). - An instance or statically allocated variable $f$ introduces a getter $f$, - and a mutable instance or statically allocated variable $f$ + A non-local variable $f$ introduces a getter $f$, + and a mutable non-local variable $f$ also introduces a setter \code{$f$=} (\ref{instanceVariables}, \ref{variables}). When we speak of members here, we mean - accessible instance or statically allocated variables, + accessible instance, static, or library variables, getters, setters, and methods (\ref{classes}). \item You cannot have two members with the same name in the same class---be @@ -17482,7 +17474,7 @@ \subsection{Type Test} but not reject any code now error-free. The rule only applies to locals and parameters, -as instance variables and statically allocated variables could be modified +as non-local variables could be modified via side-effecting functions or methods that are not accessible to a local analysis. From e171e475db7f921f3844a39890d9670b9c58a879 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 19 Jul 2023 12:36:18 +0200 Subject: [PATCH 14/15] Changed one occurrence of "static function" to "static method", which is the phrase used in the rest of that paragraph, and the topic of the section, clearly that was the intended meaning anyway --- specification/dartLangSpec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 0611bb3139..663f160fb4 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -4776,7 +4776,7 @@ \subsection{Static Methods} \rationale{% Inheritance of static methods has little utility in Dart. Static methods cannot be overridden. -Any required static function can be obtained from its declaring library, +Any required static method can be obtained from its declaring library, and there is no need to bring it into scope via inheritance. Experience shows that developers are confused by the idea of inherited methods that are not instance methods. From 3285049b58bc9ebbead4bff61285a1c60a7334af Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 19 Jul 2023 13:46:26 +0200 Subject: [PATCH 15/15] Eliminate the words mutable and immutable (instead spell out in each case which modifiers are required/assumed) --- specification/dartLangSpec.tex | 58 ++++++++++++++++------------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 663f160fb4..9ca53a7310 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -50,6 +50,10 @@ % the new meaning of that phrase). This avoids the confusion that came up % just about every single time the phrase 'static variable' came up in a % discussion. +% - Change terminology: The notion of 'mutable' and 'immutable' variables has +% been eliminated (it is spelled out each time which modifiers must be +% present or not present). The concept is confusing now where a variable can +% be late and final, and assignments to it are allowed by the static analysis. % % Mar 2023 % - Clarify how line breaks are handled in a multi-line string literal. Rename @@ -1409,19 +1413,6 @@ \section{Variables} (\ref{instanceVariables}).% } -\LMHash{}% -An \IndexCustom{immutable variable}{variable!immutable} -is a variable which cannot be bound to a different object -once it has been bound to an object. -\commentary{% -Hence, an immutable variable \id{} will always refer to the same object -after \id{} has been initialized.% -} -A variable is immutable if{}f its declaration includes -the modifier \FINAL{} or the modifier \CONST. -A \IndexCustom{mutable variable}{variable!mutable} -is a variable which is not immutable. - \subsection{Implicitly Induced Getters and Setters} \LMLabel{implicitlyInducedGettersAndSetters} @@ -1492,7 +1483,7 @@ \subsection{Implicitly Induced Getters and Setters} \LMHash{}% \Case{Setter: Mutable variable with declared type} -A mutable variable declaration of one of the forms +A variable declaration of one of the forms \begin{itemize} \item \code{\STATIC?\,\,\LATE?\,\,$T$\,\,\id;} @@ -1506,7 +1497,7 @@ \subsection{Implicitly Induced Getters and Setters} \LMHash{}% \Case{Setter: Mutable variable with no declared type, with initialization} -A mutable variable declaration of the form +A variable declaration of the form \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} implicitly induces a setter with the header \code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, @@ -1520,7 +1511,7 @@ \subsection{Implicitly Induced Getters and Setters} \LMHash{}% \Case{Setter: Mutable variable with no declared type, no initialization} -A mutable variable declaration of the form +A variable declaration of the form \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} implicitly induces a setter with the header \code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, @@ -1579,8 +1570,11 @@ \subsection{Implicitly Induced Getters and Setters} (\commentary{an extension cannot declare instance variables}). \LMHash{}% -A non-local variable introduces a setter if{}f it is mutable, -or it is late and final and does not have an initializing expression. +A non-local variable introduces a setter if{}f +it does not have the modifier \FINAL{} or the modifier \CONST{}, +or it is \LATE{} and \FINAL, but does not have an initializing expression. + +\LMHash{}% A library variable which introduces a setter will introduce a library setter into the enclosing library scope. A static variable which introduces a setter will introduce @@ -1608,7 +1602,8 @@ \subsection{Implicitly Induced Getters and Setters} is also initialized in the initializer list of $k$ (\ref{initializerLists}). -A non-late static immutable variable declaration $D$ named \id{} +A non-late static variable declaration $D$ named \id{} +that has the modifier \FINAL{} or the modifier \CONST{} does not induce a setter. However, an assignment to \id{} at a location where $D$ is in scope is not necessarily a compile-time error. @@ -1715,7 +1710,7 @@ \subsection{Evaluation of Implicit Variable Getters} \LMHash{}% If the variable $v$ has not been bound to an object then $e$ is evaluated to an object $o$. -If $v$ has now been bound to an object, and $v$ is immutable, +If $v$ has now been bound to an object, and $v$ is final, a dynamic error occurs. % Implementations throw a 'LateInitializationError'. Otherwise, $v$ is bound to $o$, and the evaluation of $g$ completes returning $o$. @@ -4707,7 +4702,7 @@ \subsubsection{Constant Constructors} \LMHash{}% It is a compile-time error if a non-redirecting generative constant constructor -is declared by a class that has a mutable instance variable. +is declared by a class that has a instance variable which is not final. \commentary{% The above refers to both locally declared and inherited instance variables.% @@ -4952,8 +4947,10 @@ \subsubsection{Inheritance and Overriding} \item There is only one namespace for getters, setters, methods and constructors (\ref{scoping}). A non-local variable $f$ introduces a getter $f$, - and a mutable non-local variable $f$ + and a non-local variable $f$ also introduces a setter + if it is not final and not constant, + or it is late and final and has no initializing expression \code{$f$=} (\ref{instanceVariables}, \ref{variables}). When we speak of members here, we mean accessible instance, static, or library variables, @@ -15392,7 +15389,7 @@ \subsection{Assignment} \LMLabel{assignment} \LMHash{}% -An assignment changes the value associated with a mutable variable, +An assignment changes the value associated with a variable, or invokes a setter. \begin{grammar} @@ -17679,10 +17676,8 @@ \subsection{Local Variable Declaration} \LMHash{}% The properties of being -\IndexCustom{initialized}{variable!initialized}, -\IndexCustom{constant}{variable!constant}, -\IndexCustom{immutable}{variable!immutable}, and -\IndexCustom{mutable}{variable!mutable} +\IndexCustom{initialized}{variable!initialized} or +\IndexCustom{constant}{variable!constant} apply to local variables with the same definitions as for other variables (\ref{variables}). @@ -17690,7 +17685,7 @@ \subsection{Local Variable Declaration} \LMHash{}% We say that a local variable $v$ is \Index{potentially mutated} in some scope $s$ -if $v$ is mutable, and an assignment to $v$ occurs in $s$. +if $v$ is not final, and an assignment to $v$ occurs in $s$. \LMHash{}% A local variable declaration of the form \code{\VAR{} $v$;} is equivalent to @@ -18194,7 +18189,9 @@ \subsubsection{For-in} \commentary{% It follows that it is a compile-time error -if $D$ is empty and \id{} is an immutable variable. +% The following error exists also in the case where \id{} is definitely +% unassigned before the loop: The loop could run >1 time. +if $D$ is empty and \id{} is a final variable. Also, it is a dynamic error if $e$ has type \DYNAMIC, but $e$ evaluates to an instance of a type which is not a subtype of \code{Iterable<\DYNAMIC>}.% @@ -18221,7 +18218,8 @@ \subsubsection{Asynchronous For-in} % This error can occur due to implicit casts and null. It is a dynamic type error if $o$ is not an instance of a class that implements \code{Stream}. -It is a compile-time error if $D$ is empty and \id{} is an immutable variable. +It is a compile-time error if $D$ is empty +and \id{} is a final or constant variable. \LMHash{}% The stream associated with the innermost enclosing asynchronous for loop,