Skip to content

Specify that initializerExpression cannot be a function literal #866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 72 additions & 17 deletions specification/dartLangSpec.tex
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
% `T` is a function type, plus other similar cases.
% - Specify actual type arguments passed to a generic function which is invoked
% with no type arguments (so it must be a dynamic invocation).
% - Specify that an <initializerExpression> cannot be a function literal. This
% does not break existing code, it has been implemented at least since 2013.
%
% 2.6
% - Specify static analysis of a "callable object" invocation (where
Expand Down Expand Up @@ -3128,9 +3130,11 @@ \subsubsection{Generative Constructors}
\LMLabel{initializerLists}

\LMHash{}%
An initializer list begins with a colon, and consists of a comma-separated list of individual \Index{initializers}.
An initializer list begins with a colon,
and consists of a comma-separated list of individual
\Index{initializers}.

\commentary{
\commentary{%
There are three kinds of initializers.
\begin{itemize}
\item[$\bullet$] A \emph{superinitializer} identifies a
Expand All @@ -3141,7 +3145,7 @@ \subsubsection{Generative Constructors}
\item[$\bullet$] An \emph{instance variable initializer}
assigns an object to an individual instance variable.
\item[$\bullet$] An assertion.
\end{itemize}
\end{itemize}%
}

\begin{grammar}
Expand All @@ -3158,11 +3162,44 @@ \subsubsection{Generative Constructors}
<initializerExpression> ::= <conditionalExpression> | <cascade>
\end{grammar}

\LMHash{}%
It is a compile-time error if a \synt{functionExpression} occurs as a subterm
(\ref{notation})
of an \synt{initializerExpression} $e$,
unless it occurs inside a subterm of $e$ which is of the form
\syntax{`(' <expression> `)'}.
Copy link
Member

@lrhn lrhn Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HOWEVER (ahem), that's probably also not precise enough, now that I got to think about it.

We do allow some function expressions that are not inside parentheses, as long as they are inside something.
Being "inside" can be inside a collection literal or string interpolation, or occurring as a function call argument, which are still clearly delimited, but not by a parenthesized expression.

So, maybe we need a definition like:

A subexpression e of another expression o is said to be undelimited in o if:

  • e is o, or
  • o is an operator expression other (infix, prefix or suffix operators)
    and e is undelimited in one of the operand expressions of o other than
    the index operand of an [] or []= operator.

Then it is a compile-time error if a function expression is undelimited in the initializer expression.

Effectively, it has to be delimited on both side, before so that we know it's coming, and after so that we know when it's done.

(It is a little curious that we can figure out C() : x = a + {};, but not C() : x = a + (){};. Maybe we're not trying hard enough).


\rationale{%
The reason for having this restriction is that
it may be necessary to scan the code
to the end of a potentially long function body in order to determine
whether that function body is the body of the constructor,
or it is the body of a function literal
which is an \synt{initializerExpression}.
This may impede the readability of the code for human beings,
and it may cause performance issues for parsers.
Also, such a function literal may capture variables from
the formal parameter initializer scope
(\ref{generativeConstructors}),
which may be error prone because such a variable has
the same name as an instance field,
but it is a distinct variable and may have a different value.%
}

\commentary{%
Assuming that this restriction did not exist, consider the following example:
`\code{C():\,\,\THIS.y\,\,=\,(x)\,\{\ldots\}}'.
If that snippet of code is followed by `\code{;}' or `\code{,}'
then `\code{(x)\,\{\ldots\}}' is a function literal,
otherwise it is the expression \code{(x)} followed by the constructor body.%
}

\LMHash{}%
An initializer of the form \code{$v$ = $e$} is equivalent to
an initializer of the form \code{\THIS{}.$v$ = $e$},
both forms are called \Index{instance variable initializers}.
It is a compile-time error if the enclosing class does not declare an instance variable named $v$.
It is a compile-time error if the enclosing class does not declare
an instance variable named $v$.
Otherwise, let $T$ be the static type of $v$.
It is a compile-time error unless the static type of $e$ is assignable to $T$.

Expand All @@ -3176,8 +3213,10 @@ \subsubsection{Generative Constructors}

\noindent{}%
Let $S$ be the superclass of the enclosing class of $s$.
It is a compile-time error if class $S$ does not declare a generative constructor named $S$ (respectively \code{$S$.\id}).
Otherwise, the static analysis of $s$ is performed as specified in Section~\ref{bindingActualsToFormals},
It is a compile-time error if class $S$ does not declare
a generative constructor named $S$ (respectively \code{$S$.\id}).
Otherwise, the static analysis of $s$ is performed
as specified in Section~\ref{bindingActualsToFormals},
as if \code{\SUPER{}} respectively \code{\SUPER{}.\id}
had had the function type of the denoted constructor,
%% TODO(eernst): The following is very imprecise, it just serves to remember
Expand All @@ -3190,14 +3229,25 @@ \subsubsection{Generative Constructors}

\LMHash{}%
Let $k$ be a generative constructor.
Then $k$ may include at most one superinitializer in its initializer list or a compile-time error occurs.
If no superinitializer is provided, an implicit superinitializer of the form \SUPER{}() is added at the end of $k$'s initializer list,
Then $k$ may include at most one superinitializer in its initializer list
or a compile-time error occurs.
If no superinitializer is provided,
an implicit superinitializer of the form \SUPER{}() is added
at the end of $k$'s initializer list,
unless the enclosing class is class \code{Object}.
It is a compile-time error if a superinitializer appears in $k$'s initializer list at any other position than at the end.
It is a compile-time error if more than one initializer corresponding to a given instance variable appears in $k$'s initializer list.
It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is initialized by means of an initializing formal of $k$.
It is a compile-time error if $k$'s initializer list contains an initializer for a final variable $f$ whose declaration includes an initialization expression.
It is a compile-time error if $k$ includes an initializing formal for a final variable $f$ whose declaration includes an initialization expression.
It is a compile-time error if a superinitializer appears
in $k$'s initializer list at any other position than at the end.
It is a compile-time error if more than one initializer corresponding to
a given instance variable appears in $k$'s initializer list.
It is a compile-time error if $k$'s initializer list contains
an initializer for a variable that is initialized by means of
an initializing formal of $k$.
It is a compile-time error if $k$'s initializer list contains
an initializer for a final variable $f$ whose declaration includes
an initialization expression.
It is a compile-time error if $k$ includes an initializing formal for
a final variable $f$ whose declaration includes
an initialization expression.

\LMHash{}%
Let $f$ be a final instance variable declared in
Expand All @@ -3211,14 +3261,19 @@ \subsubsection{Generative Constructors}
\end{itemize}

\LMHash{}%
It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is not an instance variable declared in the immediately surrounding class.
It is a compile-time error if $k$'s initializer list contains
an initializer for a variable that is not
an instance variable declared in the immediately surrounding class.

\commentary{
The initializer list may of course contain an initializer for any instance variable declared by the immediately surrounding class, even if it is not final.
\commentary{%
The initializer list may of course contain an initializer for
any instance variable declared by the immediately surrounding class,
even if it is not final.%
}

\LMHash{}%
It is a compile-time error if a generative constructor of class \code{Object} includes a superinitializer.
It is a compile-time error if a generative constructor of class \code{Object}
includes a superinitializer.


\paragraph{Execution of Generative Constructors}
Expand Down