Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
4 changes: 4 additions & 0 deletions specification/dart.sty
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@
\newcommand{\MutualSubtypeStd}[2]{\MutualSubtype{\Delta}{#1}{#2}}
\newcommand{\MutualSubtypeNE}[2]{\ensuremath{{#1}\,<:>\,{#2}}}

% Judgment expressing that a type is a subtype of the union base type
% of another.
\newcommand\UnionBasedSubtype[2]{\ensuremath{#1\,\cup\!\EXTENDS\,\,\,#2}}
Comment thread
eernstg marked this conversation as resolved.
Outdated

% Judgment expressing that a supertype relation exists.
\newcommand{\Supertype}[3]{\ensuremath{{#1}\vdash{#2}\,:>\,{#3}}}
\newcommand{\SupertypeStd}[2]{\Supertype{\Delta}{#1}{#2}}
Expand Down
75 changes: 62 additions & 13 deletions specification/dartLangSpec.tex
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
% version of the language which will actually be specified by the next stable
% release of this document.
%
% Aug 2026
% - Define the union base type of a type, make union based cycles in type
% parameter declarations a compile-time error.
%
% Jul 2026
% - Remove the getter/setter signature mismatch error. It is no longer required
% that the getter return type and setter parameter type are related in any way.
Expand Down Expand Up @@ -2160,15 +2164,14 @@ \section{Functions}

\LMHash{}%
We define the
\Index{union-free type derived from}
a type $T$ as follows:
\Index{union base type}
of a type $T$ as follows:
If $T$ is of the form \code{$S$?}\ or the form \code{FutureOr<$S$>}
then the union-free type derived from $T$ is
the union-free type derived from $S$.
Otherwise, the union-free type derived from $T$ is $T$.
then the union base type of $T$ is
the union base type of $S$.
Otherwise, the union base type of $T$ is $T$.
\commentary{%
For example, the union-free type derived from
\code{FutureOr<int?>?} is \code{int}.%
For example, the union base type of \code{FutureOr<int?>?} is \code{int}.%
}

\LMHash{}%
Expand All @@ -2177,7 +2180,7 @@ \section{Functions}
function!generator!element type}
$f$ as follows:
%
Let $S$ be the union-free type derived from the declared return type of $f$.
Let $S$ be the union base type of the declared return type of $f$.
%
If $f$ is a synchronous generator and
$S$ implements \code{Iterable<$U$>} for some $U$
Expand Down Expand Up @@ -7439,15 +7442,61 @@ \section{Generics}
\LMHash{}%
A type parameter $T$ may be suffixed with an \EXTENDS{} clause
that specifies the \Index{upper bound} for $T$.
If no \EXTENDS{} clause is present, the upper bound is \code{Object}.
It is a compile-time error if a type parameter is a supertype of its upper bound
when that upper bound is itself a type variable.
If no \EXTENDS{} clause is present, the upper bound is \code{Object?}.

\LMHash{}%
We need to define a special subset of the clauses \code{$X$\,\,\EXTENDS\,\,$B$}
Comment thread
eernstg marked this conversation as resolved.
Outdated
Comment thread
eernstg marked this conversation as resolved.
Outdated
in order to avoid a certain kind of cycles.
Let
\IndexCustom{\UnionBasedSubtype{X}{Y}}{$\cup$@$X\,\,\,\textsf{U}\EXTENDS\,\,Y$}
be the relation among type variables $X$ and $Y$ where
\code{$X$\,\,\EXTENDS\,\,$Y$}, or
Comment thread
eernstg marked this conversation as resolved.
Outdated
\code{$X$\,\,\EXTENDS\,\,$T$}
where $T$ is a type whose union base type
(\ref{functions})
is $Y$.
\commentary{%
For example, \UnionBasedSubtype{X}{X}
when \code{$X$\,\,\EXTENDS\,\,$X$},
when \code{$X$\,\,\EXTENDS\,\,$X$?},
and when \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and
\UnionBasedSubtype{X}{Y} when
\code{$X$\,\,\EXTENDS\,\,FutureOr<FutureOr<$Y$?>{}>?}.%
}

\LMHash{}%
It is a \Error{compile-time error} if a generic declaration $D$ has
Comment thread
eernstg marked this conversation as resolved.
Outdated
type parameters and bounds
\code{$X_1$\,\,\EXTENDS\,\,$B_1$,\,\dots,\,$X_s$\,\,\EXTENDS\,\,$B_s$} such that
\UnionBasedSubtype{X_j}{X_{j+1}} for all $j \in 1 .. s - 1$,
and \UnionBasedSubtype{X_s}{X_1}
\commentary{(that is, $B_s$ is $X_1$, possibly wrapped in some unions)}.
These type parameters can be declared in any order,
Comment thread
eernstg marked this conversation as resolved.
Outdated
and there may be additional type parameters declared by $D$,
the requirement is just that the cycle exists.
\commentary{%
This prevents circular declarations like
\code{X \EXTENDS{} X}
\code{X\,\,\EXTENDS\,\,X}
and
\code{X\,\,\EXTENDS\,\,Y, Y\,\,\EXTENDS\,\,X}.
It also prevents pseudo-circular declarations like
\code{X\,\,\EXTENDS\,\,X?}
and
\code{X \EXTENDS{} Y, Y \EXTENDS{} X}.%
\code{X\,\,\EXTENDS\,\,FutureOr<Y>, Y\,\,\EXTENDS\,\,X}.%
}

\rationale{%
A type parameter declaration like
\code{X\,\,\EXTENDS\,\,X} or \code{X\,\,\EXTENDS\,\,X?}
could just as well have omitted the bound because it is always satisfied.
Similarly, a pseudo-circular declaration like
\code{X\,\,\EXTENDS\,\,FutureOr<Y>, Y\,\,\EXTENDS\,\,X}
is satisfied when all type variables are bound to a top type,
or a couple of other cases involving bottom types and \code{Object},
which is not likely to be useful.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe not.

You can always satisfy the bounds, but if you have <X extends Y, Y extends FutureOf<X>>, you can assign Y to X, and await (x as X) to Y. You couldn't do that if you removed the bounds, and you can't just collapse them to one type variable, that wouldn't have the two different bounds.

You could likely have reduced all of the variables to a single type variable with no bound, and added the FutureOr and ? on occurrences as needed. Maybe.

But more relevantly FutureOr and ? are structural, so X extends FutureOf<X> has an infinitive expansion if one tries to be eager. That's bad.
(A cycle with no union type shouldn't be a problem if it can be detected, it's just useless.)

We avoid these cycles and pseudo-cycles because
they can introduce infinite loops into the computation of
standard upper bounds and subtyping.%
}

\LMHash{}%
Expand Down