Index: docs/language/dartLangSpec.tex |
=================================================================== |
--- docs/language/dartLangSpec.tex (revision 44473) |
+++ docs/language/dartLangSpec.tex (working copy) |
@@ -3092,10 +3092,12 @@ |
The static type of a function literal of the form |
$(T_1$ $a_1, \ldots, T_n$ $a_n, [T_{n+1}$ $x_{n+1} = d_1, \ldots, T_{n+k}$ $x_{n+k} = d_k])$ \ASYNC{} $=> e$ |
-is $(T_1 \ldots, T_n, [T_{n+1}$ $x_{n+1}, \ldots, T_{n+k}$ $x_{n+k}]) \rightarrow Future<flatten(T_0)>$, where $T_0$ is the static type of $e$ and $flatten(T) = flatten(S)$ if $T = Future<S>$, and $T$ otherwise. |
+is $(T_1 \ldots, T_n, [T_{n+1}$ $x_{n+1}, \ldots, T_{n+k}$ $x_{n+k}]) \rightarrow Future<flatten(T_0)>$, where $T_0$ is the static type of $e$ and $flatten(T) = flatten(S)$ if $T = Future<S>$ and $T \ne S$, and $T$ otherwise. |
Paul Berry
2015/03/13 19:59:11
I'm confused as to why $T \ne S$ is necessary. Do
Lasse Reichstein Nielsen
2015/03/15 11:53:15
I think we should flatten if T is a subtype of Fut
gbracha
2015/03/16 20:25:23
The intent was to use subtyping, not equality, but
|
\rationale{ |
We collapse multiple layers of futures into one. If $e$ evaluates to a future $f$, the future will not invoke its \code{then()} callback until f completes to a non-future value, and so the result of an await is never a future, and the result of an async function will never have type \code{Future$<X>$} where $X$ itself is an invocation of \code{Future}. |
+ |
+The sole exception to that would be a type $X$ that extended or implemented \code{Future$<X>$}. In that case, the result type is $X$ and no further unwrapping takes place. |
Paul Berry
2015/03/13 19:59:11
This is in a \rationale block, so I would expect t
Lasse Reichstein Nielsen
2015/03/15 11:53:15
So, as stated above, I disagree with that choice.
Paul Berry
2015/03/15 13:57:22
Understood. What I wish we could say is:
flatt
|
} |
@@ -5913,6 +5915,14 @@ |
} |
\LMHash{} |
+Otherwise, if the enclosing function $m$ is marked \ASYNC* (\ref{functions}) then the enclosing function may suspend. |
Lasse Reichstein Nielsen
2015/03/15 11:53:15
I still think it should be "must suspend". If that
gbracha
2015/03/16 20:25:22
Per discussion with Lars, we are not doing that. T
|
+ |
+\rationale { |
+If a \YIELD{} occurred inside an infinite loop and the enclosing function never suspended, there might not be an opportunity for consumers of the enclosing stream to run and access the data in the stream. The stream might then accumulate an unbounded number of elements. Such a situation is untenable. Therefore, we allow the enclosing function to be suspended when a new value is added to its associated stream. However, it is not essential (and in fact, can be quite costly) to suspend the function on every \YIELD{}. The implementation is free to decide how often to suspend the enclosing function. The only requirement is that consumers are not blocked indefinitely. |
+} |
+ |
+ |
+\LMHash{} |
If the enclosing function $m$ is marked \SYNC* (\ref{functions}) then: |
\begin{itemize} |
\item |
@@ -5947,28 +5957,40 @@ |
\end{grammar} |
\LMHash{} |
-Execution of a statement s of the form \code{\YIELD* $e$;} proceeds as follows: |
+Execution of a statement $s$ of the form \code{\YIELD* $e$;} proceeds as follows: |
\LMHash{} |
-First, the expression $e$ is evaluated to an object $o$. If the immediately enclosing function $m$ is synchronous, then it is a dynamic error if the class of $o$ does not implement \code{Iterable}. If $m$ asynchronous, then it is a dynamic error if the class of $o$ does not implement \code{Stream}. Next, for each element $x$ of $o$: |
-\begin{itemize} |
+First, the expression $e$ is evaluated to an object $o$. |
+ |
+\LMHash{} |
+If the immediately enclosing function $m$ is marked \SYNC* (\ref{functions}), then: |
+\begin{enumerate} |
+\item It is a dynamic error if the class of $o$ does not implement \code{Iterable}. Otherwise |
Lasse Reichstein Nielsen
2015/03/15 11:53:15
Still think this line should be dropped. If you ca
gbracha
2015/03/16 20:25:22
My goal in this CL is to deal with oversights and
|
+\item The method \cd{iterator} is invoked upon $o$ returning an object $i$. |
Lasse Reichstein Nielsen
2015/03/15 11:53:16
Or it may throw - implementing an interface doesn'
|
+\item \label{moveNext} The \cd{moveNext} method of $i$ is invoked. If \cd{moveNext} returns \FALSE{} execution of $s$ is complete. Otherwise |
Lasse Reichstein Nielsen
2015/03/15 11:53:16
Should we say the the moveNext method of i is invo
Lasse Reichstein Nielsen
2015/03/15 11:53:16
The result of moveNext should be subjected to bool
gbracha
2015/03/16 22:21:40
Done.
|
+\item An element $x$ is extracted from $i$ and $x$ is added to the iterable or stream associated with $m$. |
Lasse Reichstein Nielsen
2015/03/15 11:53:16
"extracted from" doesn't say how.
What you do is
gbracha
2015/03/16 22:21:40
But for streams it's a bit different. So I abstrac
Lasse Reichstein Nielsen
2015/03/17 07:11:21
It's very different for Stream, but this text only
|
+Execution of the function $m$ immediately enclosing $s$ is suspended until the method \code{moveNext()} is invoked upon the iterator used to initiate the current invocation of $m$, at which point execution of $s$ continues at \ref{moveNext}. |
\item |
-If $m$ is marked \ASYNC* (\ref{functions}) and the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled. |
-\item |
- $x$ is added to the iterable or stream associated with $m$ in the order it appears in $o$. |
- \item |
-If $m$ is marked \ASYNC* and the stream $u$ associated with $m$ has been canceled, then let $c$ be the \FINALLY{} clause (\ref{try}) of the innermost enclosing try-finally statement, if any. If $c$ is defined, let $h$ be the handler induced by $c$. If $h$ is defined, control is transferred to $h$. If $h$ is undefined, the immediately enclosing function terminates. |
-\end{itemize} |
+The current call to \code{moveNext()} returns \TRUE. |
+\end{enumerate} |
\LMHash{} |
-If the enclosing function is marked \SYNC* (\ref{functions}) then: |
+If $m$ is marked \ASYNC* (\ref{functions}), then: |
\begin{itemize} |
+\item It is a dynamic error if the class of $o$ does not implement \code{Stream}. Otherwise |
+\item For each element $x$ of $o$: |
+\begin{itemize} |
\item |
-Execution of the function $m$ immediately enclosing $s$ is suspended until the method \code{moveNext()} is invoked upon the iterator used to initiate the current invocation of $m$. |
+If the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled. |
+ \item |
+If the stream $u$ associated with $m$ has been canceled, then let $c$ be the \FINALLY{} clause (\ref{try}) of the innermost enclosing try-finally statement, if any. If $c$ is defined, let $h$ be the handler induced by $c$. If $h$ is defined, control is transferred to $h$. If $h$ is undefined, the immediately enclosing function terminates. |
\item |
-The current call to \code{moveNext()} returns \TRUE. |
+Otherwise, $x$ is added to the stream associated with $m$ in the order it appears in $o$. The function $m$ may suspend. |
\end{itemize} |
+\item If the stream $o$ is done, execution of $s$ is complete. |
+\end{itemize} |
+ |
\LMHash{} |
It is a compile-time error if a yield-each statement appears in a function that is not a generator function. |