-
Notifications
You must be signed in to change notification settings - Fork 215
Update flatten definition #2713
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
Changes from 4 commits
9c3c9e9
03375fa
2f0b777
0cd0960
5f1c339
49307ea
4f450ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11275,35 +11275,56 @@ \subsection{Function Expressions} | |
where inferred types have already been added.% | ||
} | ||
|
||
\LMHash{}% | ||
We define the | ||
\IndexCustom{future type of a type}{type!future type of} | ||
$T$ as follows: | ||
|
||
\begin{itemize} | ||
\item If $T$ implements \code{Future<$S$>} | ||
(\ref{interfaceSuperinterfaces}) | ||
then the future type of $T$ is \code{Future<$S$>}. | ||
\item Otherwise, if $T$ is \code{FutureOr<$S$>} bounded | ||
(\ref{bindingActualsToFormals}) | ||
then the future type of $T$ is \code{FutureOr<$S$>}. | ||
eernstg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
\item Otherwise, if $T$ is \code{Future<$S$>?} bounded | ||
or \code{FutureOr<$S$>?} bounded | ||
then the future type of $T$ is \code{Future<$S$>?} | ||
respectively \code{FutureOr<$S$>?}. | ||
eernstg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
\item Otherwise, $T$ has no future type. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does not seem to account for Maybe:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
About the rulesets:
This is my first item.
This is different, but flatten would take those two different intermediate results to the same end result.
This is somewhat redundant: It may include a usage of the first item, but it would then already be covered by the first item.
I could use this to make the third item simpler, but it would only be applicable in some cases after having applied item 2.
OK, I don't see any discrepancies so we could use one or the other definition, but it's not obvious to me that this one is simpler to reason about. |
||
\end{itemize} | ||
|
||
\LMHash{}% | ||
We define the auxiliary function | ||
\IndexCustom{\flatten{T}}{flatten(t)@\emph{flatten}$(T)$}, | ||
which is used below and in other sections, as follows: | ||
|
||
\begin{itemize} | ||
\item{} If $T$ is \code{$S$?}\ bounded | ||
(\ref{bindingActualsToFormals}) | ||
for some $S$ then \DefEquals{\flatten{T}}{\code{\flatten{S}?}}. | ||
\item If $T$ is \code{$S$?}\ for some $S$ | ||
then \DefEquals{\flatten{T}}{\code{\flatten{S}?}}. | ||
|
||
\item{} If $T$ is \code{FutureOr<$S$>} bounded | ||
then \DefEquals{\flatten{T}}{S}. | ||
\item Otherwise, if $T$ is \code{$X$\,\,\&\,\,$S$} | ||
for some type variable $X$ and type $S$ then | ||
\begin{itemize} | ||
\item if $S$ has future type $U$ | ||
then \DefEquals{\flatten{T}}{\code{\flatten{U}}}. | ||
\item otherwise, | ||
\DefEquals{\flatten{T}}{\code{\flatten{X}}}. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... which falls back to case-analysis on the bound of I'd say Example:
It's not unsound, because a result type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes flatten( But I guess you're saying that if the developer tests explicitly for It is not obvious to me that this would be the natural behavior. I tend to think it's OK to find the future type in the type variable in the case where the other operand of the intersection type doesn't have any. |
||
\end{itemize} | ||
|
||
\item{} If $T$ implements \code{Future<$S$>} | ||
(\ref{interfaceSuperinterfaces}) | ||
\item Otherwise, if $T$ has future type \code{Future<$S$>} | ||
or \code{FutureOr<$S$>} | ||
then \DefEquals{\flatten{T}}{S}. | ||
|
||
\item{} Otherwise, \DefEquals{\flatten{T}}{T}. | ||
\item Otherwise, if $T$ has future type \code{Future<$S$>?}\ or | ||
\code{FutureOr<$S$>?}\ then \DefEquals{\flatten{T}}{\code{$S$?}}. | ||
eernstg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
\item Otherwise, \DefEquals{\flatten{T}}{T}. | ||
\end{itemize} | ||
|
||
\commentary{% | ||
\rationale{% | ||
This definition guarantees that for any type $T$, | ||
\code{$T <:$ FutureOr<$\flatten{T}$>}. | ||
Note that when $X$ is a type variable with bound $B$, | ||
it is possible that \flatten{X} is different from $X$: | ||
$B$ could, for some $S$, be \code{FutureOr<$S$>}, | ||
or a type variable $Y$ with bound \code{FutureOr<$S$>}, | ||
or a class $C$ that implements \code{Future<$S$>}, | ||
or a type variable $X$ with bound $C$.% | ||
\code{$T <:$ FutureOr<$\flatten{T}$>}.% | ||
} | ||
|
||
\LMHash{}% | ||
|
@@ -15992,27 +16013,25 @@ \subsection{Await Expressions} | |
\end{grammar} | ||
|
||
\LMHash{}% | ||
Evaluation of an await expression $a$ of the form \code{\AWAIT{} $e$} | ||
where $e$ has static type $S$ proceeds as follows: | ||
First, the expression $e$ is evaluated to an object $o$. | ||
Let $T$ be \flatten{S} | ||
(\flatten{} is defined in section \ref{functionExpressions}). | ||
It is a dynamic type error if the run-time type of $o$ is not a subtype | ||
of \code{FutureOr<$T$>} \commentary{(that is, if it is neither a subtype | ||
of $T$ nor of \code{Future<$T$>})}. | ||
\BlindDefineSymbol{a, e, S}% | ||
Let $a$ be an expression of the form \code{\AWAIT\,\,$e$}. | ||
Let $S$ be the static type of $e$. | ||
The static type of $a$ is then \flatten{S} | ||
(\ref{functionExpressions}). | ||
|
||
\LMHash{}% | ||
% NOTICE: Removed the requirement that an error thrown by $e$ is caught in a | ||
% future. There is no reason $var x = e; await x;$ and $await e$ should behave | ||
% differently, and no implementation actually implemented it. | ||
Evaluation of $a$ proceeds as follows: | ||
First, the expression $e$ is evaluated to an object $o$. | ||
Let \DefineSymbol{T} be \flatten{S}. | ||
If the run-time type of $o$ is a subtype of \code{Future<$T$>}, | ||
then let $f$ be $o$; | ||
then let \DefineSymbol{f} be $o$; | ||
otherwise let $f$ be the result of creating | ||
a new object using the constructor \code{Future<$T$>.value()} | ||
with $o$ as its argument. | ||
|
||
\LMHash{}% | ||
Next, the stream associated with the innermost enclosing asynchronous for loop | ||
Next, the stream associated with | ||
the innermost enclosing asynchronous \FOR{} loop | ||
(\ref{asynchronousFor-in}), | ||
if any, is paused. | ||
The current invocation of the function body immediately enclosing $a$ | ||
|
@@ -16023,8 +16042,33 @@ \subsection{Await Expressions} | |
(\ref{expressionEvaluation}). | ||
If $f$ completes with an object $v$, $a$ evaluates to $v$. | ||
|
||
% Otherwise, the value of $a$ is the value of $e$. If evaluation of | ||
% $e$ raises an exception $x$, $a$ raises $x$. | ||
\rationale{% | ||
This use of \flattenName{} implies that we await a future | ||
in every case where this choice is sound.% | ||
eernstg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
\commentary{% | ||
An interesting case on the edge of this trade-off is when $e$ | ||
has the static type \code{FutureOr<Object>?}. | ||
You could say that the intention behind this type is that | ||
the value of $e$ is a \code{Future<Object>}, | ||
or it is an \code{Object} which is not a future, | ||
or it is \NULL. | ||
So, presumably, we should await the first kind, | ||
and we should pass on the second and third kind unchanged. | ||
However, the second kind could be a \code{Future<Object?>}. | ||
This object isn't a \code{Future<Object>}, and it isn't \NULL, | ||
so it \emph{must} be considered to be in the second group. | ||
Nevertheless, \flatten{\code{FutureOr<Object>?}} is \code{Object?}, | ||
so we \emph{will} await a \code{Future<Object?>}. | ||
We have chosen this semantics because it was the smallest breaking change | ||
relative to the semantics in earlier versions of Dart, | ||
and also because it allows for a simple rule: | ||
The type of \code{\AWAIT\,\,$e$} is used to decide whether or not | ||
the future (if any) is awaited, and there are no exceptions---even | ||
in cases like this example, where the type seems to imply that | ||
a \code{Future<Object?>} should not be awaited.% | ||
eernstg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
\commentary{% | ||
An await expression can only occur in a function which is declared | ||
|
@@ -16047,9 +16091,6 @@ \subsection{Await Expressions} | |
Tools may choose to give a hint in such cases.% | ||
} | ||
|
||
\LMHash{}% | ||
The static type of $a$ is $T$. | ||
|
||
|
||
\subsection{Postfix Expressions} | ||
\LMLabel{postfixExpressions} | ||
|
Uh oh!
There was an error while loading. Please reload this page.