From e3f94a55fc410b4bddd7ed158363a6b5edeceb54 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 7 Aug 2026 18:40:24 +0200 Subject: [PATCH 01/12] Specify 433 --- specification/dart.sty | 4 ++ specification/dartLangSpec.tex | 74 +++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/specification/dart.sty b/specification/dart.sty index db1a0f8dbf..8a5d143faf 100644 --- a/specification/dart.sty +++ b/specification/dart.sty @@ -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}} + % Judgment expressing that a supertype relation exists. \newcommand{\Supertype}[3]{\ensuremath{{#1}\vdash{#2}\,:>\,{#3}}} \newcommand{\SupertypeStd}[2]{\Supertype{\Delta}{#1}{#2}} diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 92aba3d8f4..61ed3a0c72 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -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. @@ -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?} is \code{int}.% + For example, the union base type of \code{FutureOr?} is \code{int}.% } \LMHash{}% @@ -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$ @@ -7439,15 +7442,58 @@ \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?}. +It is a \Error{compile-time error} if a type parameter is a supertype of +its upper bound when that upper bound is itself a type variable. \commentary{% This prevents circular declarations like - \code{X \EXTENDS{} X} + \code{X\,\,\EXTENDS\,\,X} + and + \code{X\,\,\EXTENDS\,\,Y, Y\,\,\EXTENDS\,\,X}.% +} + +\LMHash{}% +We need to define a special subset of the clauses \code{$X$\,\,\EXTENDS\,\,$B$} +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 +\code{$X$\,\,\EXTENDS\,\,$T$} +where $T$ is a type whose union base type +(\ref{functions}) +is $Y$. +\commentary{% + As an example, \UnionBasedSubtype{X}{X\code{?}} and + \UnionBasedSubtype{X}{\code{FutureOr<$X$>}}, but also + \UnionBasedSubtype{X}{\code{FutureOr{}>?}}.% +} + +\LMHash{}% +It is a \Error{compile-time error} if a generic declaration $D$ has +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}. +These type parameters can be declared in any order, +and there may be additional type parameters declared by $D$, +the requirement is just that the cycle exists. +\commentary{% + This prevents pseudo-circular declarations like + \code{X\,\,\EXTENDS\,\,X?} and - \code{X \EXTENDS{} Y, Y \EXTENDS{} X}.% + \code{X\,\,\EXTENDS\,\,FutureOr, Y\,\,\EXTENDS\,\,X}.% +} + +\rationale{% + A type parameter declaration like \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\,\,\EXTENDS\,\,X} + is satisfied when all type variables in the cycle have the same value, + at least when that type is a top type, which is not likely to be useful. + We avoid these pseudo-cycle because they can introduce infinite loops + into the computation of standard upper bounds and subtyping.% } \LMHash{}% From ee658d2f19ad34715ba9b5bc2ab67560cbb20aa1 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Sun, 9 Aug 2026 11:38:41 +0200 Subject: [PATCH 02/12] Typo --- specification/dartLangSpec.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 61ed3a0c72..e2c27f1881 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7474,7 +7474,8 @@ \section{Generics} 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}. +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, and there may be additional type parameters declared by $D$, the requirement is just that the cycle exists. From 658fb4de3f69b7973787e21a24843e3ce27542ab Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Sun, 9 Aug 2026 11:46:09 +0200 Subject: [PATCH 03/12] Improve rationale --- specification/dartLangSpec.tex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index e2c27f1881..2cc291e8b4 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7491,8 +7491,9 @@ \section{Generics} could just as well have omitted the bound because it is always satisfied. Similarly, a pseudo-circular declaration like \code{X\,\,\EXTENDS\,\,FutureOr, Y\,\,\EXTENDS\,\,X} - is satisfied when all type variables in the cycle have the same value, - at least when that type is a top type, which is not likely to be useful. + 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. We avoid these pseudo-cycle because they can introduce infinite loops into the computation of standard upper bounds and subtyping.% } From 990d470715ff670df0ae59b7e15643bc005e3d74 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Sun, 9 Aug 2026 11:47:53 +0200 Subject: [PATCH 04/12] Typo --- specification/dartLangSpec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 2cc291e8b4..d3f6c299b5 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7494,7 +7494,7 @@ \section{Generics} 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. - We avoid these pseudo-cycle because they can introduce infinite loops + We avoid these pseudo-cycles because they can introduce infinite loops into the computation of standard upper bounds and subtyping.% } From 1fd98c99d6a5d445c43e803376139916a100d9dc Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Sun, 9 Aug 2026 11:57:11 +0200 Subject: [PATCH 05/12] Correct examples --- specification/dartLangSpec.tex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index d3f6c299b5..c7fb6456b1 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7464,9 +7464,11 @@ \section{Generics} (\ref{functions}) is $Y$. \commentary{% - As an example, \UnionBasedSubtype{X}{X\code{?}} and - \UnionBasedSubtype{X}{\code{FutureOr<$X$>}}, but also - \UnionBasedSubtype{X}{\code{FutureOr{}>?}}.% + As an example, \UnionBasedSubtype{X}{X} + when \code{$X$\,\,\EXTENDS\,\,$X$?} and + when \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and + \UnionBasedSubtype{X}{Y} when + \code{$X$\,\,\EXTENDS\,\,FutureOr{}>?}.% } \LMHash{}% From c8594aa03457a41f41f1f4d148086a40ab4a5e10 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Mon, 10 Aug 2026 14:40:01 +0000 Subject: [PATCH 06/12] Remove the old rule about type variable cycles which is now obsolete --- specification/dartLangSpec.tex | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index c7fb6456b1..4a7f86e173 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7443,14 +7443,6 @@ \section{Generics} 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 \Error{compile-time error} if a type parameter is a supertype of -its upper bound when that upper bound is itself a type variable. -\commentary{% - This prevents circular declarations like - \code{X\,\,\EXTENDS\,\,X} - and - \code{X\,\,\EXTENDS\,\,Y, Y\,\,\EXTENDS\,\,X}.% -} \LMHash{}% We need to define a special subset of the clauses \code{$X$\,\,\EXTENDS\,\,$B$} @@ -7464,9 +7456,10 @@ \section{Generics} (\ref{functions}) is $Y$. \commentary{% - As an example, \UnionBasedSubtype{X}{X} - when \code{$X$\,\,\EXTENDS\,\,$X$?} and - when \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and + For example, \UnionBasedSubtype{X}{X} + when \code{$X$\,\,\EXTENDS\,\,$X$}, + \code{$X$\,\,\EXTENDS\,\,$X$?}, + or \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and \UnionBasedSubtype{X}{Y} when \code{$X$\,\,\EXTENDS\,\,FutureOr{}>?}.% } @@ -7482,22 +7475,28 @@ \section{Generics} and there may be additional type parameters declared by $D$, the requirement is just that the cycle exists. \commentary{% - This prevents pseudo-circular declarations like + This prevents circular declarations like + \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\,\,FutureOr, Y\,\,\EXTENDS\,\,X}.% } \rationale{% - A type parameter declaration like \code{X\,\,\EXTENDS\,\,X?} + 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\,\,\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. - We avoid these pseudo-cycles because they can introduce infinite loops - into the computation of standard upper bounds and subtyping.% + We avoid these cycles and pseudo-cycles because + they can introduce infinite loops into the computation of + standard upper bounds and subtyping.% } \LMHash{}% From 4be641448ed4662dc2976b8fae4731fde9eeb53e Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Mon, 10 Aug 2026 14:45:54 +0000 Subject: [PATCH 07/12] Correct commentary --- specification/dartLangSpec.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 4a7f86e173..6576372a1d 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7458,8 +7458,8 @@ \section{Generics} \commentary{% For example, \UnionBasedSubtype{X}{X} when \code{$X$\,\,\EXTENDS\,\,$X$}, - \code{$X$\,\,\EXTENDS\,\,$X$?}, - or \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and + when \code{$X$\,\,\EXTENDS\,\,$X$?}, + and when \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and \UnionBasedSubtype{X}{Y} when \code{$X$\,\,\EXTENDS\,\,FutureOr{}>?}.% } From db2c4dab2018f90c31e2a44762ef656da2ff9ff8 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 12 Aug 2026 13:02:28 +0000 Subject: [PATCH 08/12] WIP --- specification/dartLangSpec.tex | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 6576372a1d..11e54f5bf9 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7445,22 +7445,22 @@ \section{Generics} 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$} -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 +We say that +\IndexCustom{$X$ union-extends $Y$}{union-extends} +when $X$ and $Y$ are type variables, +and $X$ is declared as \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 + For example, $X$ union-extends $X$ + when $X$ is declared as + \code{$X$\,\,\EXTENDS\,\,$X$}, + \code{$X$\,\,\EXTENDS\,\,$X$?}, or + \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and + $X$ union-extends $Y$ when $X$ is declared as \code{$X$\,\,\EXTENDS\,\,FutureOr{}>?}.% } From b72728ee6fa53b782803fe3b4f208061e48d7d8e Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 12 Aug 2026 13:13:53 +0000 Subject: [PATCH 09/12] WIP --- specification/dart.sty | 4 ---- specification/dartLangSpec.tex | 17 ++++++++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/specification/dart.sty b/specification/dart.sty index 8a5d143faf..db1a0f8dbf 100644 --- a/specification/dart.sty +++ b/specification/dart.sty @@ -478,10 +478,6 @@ \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}} - % Judgment expressing that a supertype relation exists. \newcommand{\Supertype}[3]{\ensuremath{{#1}\vdash{#2}\,:>\,{#3}}} \newcommand{\SupertypeStd}[2]{\Supertype{\Delta}{#1}{#2}} diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 11e54f5bf9..1838d349b8 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7457,8 +7457,8 @@ \section{Generics} \commentary{% For example, $X$ union-extends $X$ when $X$ is declared as - \code{$X$\,\,\EXTENDS\,\,$X$}, - \code{$X$\,\,\EXTENDS\,\,$X$?}, or + \code{$X$\,\,\EXTENDS\,\,$X$}, as + \code{$X$\,\,\EXTENDS\,\,$X$?}, or as \code{$X$\,\,\EXTENDS\,\,FutureOr<$X$>}, and $X$ union-extends $Y$ when $X$ is declared as \code{$X$\,\,\EXTENDS\,\,FutureOr{}>?}.% @@ -7467,13 +7467,12 @@ \section{Generics} \LMHash{}% It is a \Error{compile-time error} if a generic declaration $D$ has 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, -and there may be additional type parameters declared by $D$, -the requirement is just that the cycle exists. +\code{$X_1$\,\,\EXTENDS\,\,$B_1$,\,\dots,\,$X_s$\,\,\EXTENDS\,\,$B_s$}, +declared in any textual order and potentially together with additional +type parameters, +such that +$X_j$ union-extends $X_{j+1}$ for all $j \in 1 .. s - 1$, +and $X_s$ union-extends $X_1$. \commentary{% This prevents circular declarations like \code{X\,\,\EXTENDS\,\,X} From fbe3f4a7e68ad2715159c1771df886cb0a85e434 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 12 Aug 2026 13:19:08 +0000 Subject: [PATCH 10/12] WIP --- specification/dartLangSpec.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 1838d349b8..835cf2ad56 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7486,7 +7486,8 @@ \section{Generics} \rationale{% A type parameter declaration like - \code{X\,\,\EXTENDS\,\,X} or \code{X\,\,\EXTENDS\,\,X?} + \code{X\,\,\EXTENDS\,\,X} or \code{X\,\,\EXTENDS\,\,X?} or + \code{X\,\,\EXTENDS\,\,FutureOr} could just as well have omitted the bound because it is always satisfied. Similarly, a pseudo-circular declaration like \code{X\,\,\EXTENDS\,\,FutureOr, Y\,\,\EXTENDS\,\,X} From ef0f77c830298e8f8360a5de77417678998792f9 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 12 Aug 2026 13:27:15 +0000 Subject: [PATCH 11/12] WIP --- specification/dartLangSpec.tex | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 835cf2ad56..246060781e 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7465,14 +7465,16 @@ \section{Generics} } \LMHash{}% -It is a \Error{compile-time error} if a generic declaration $D$ has -type parameters and bounds +A generic declaration $D$ has \Index{cyclic bounds} if it has +type parameter declarations \code{$X_1$\,\,\EXTENDS\,\,$B_1$,\,\dots,\,$X_s$\,\,\EXTENDS\,\,$B_s$}, -declared in any textual order and potentially together with additional +declared in any textual order and potentially along with additional type parameters, such that $X_j$ union-extends $X_{j+1}$ for all $j \in 1 .. s - 1$, and $X_s$ union-extends $X_1$. +It is a \Error{compile-time error} if a generic declaration +has cyclic bounds. \commentary{% This prevents circular declarations like \code{X\,\,\EXTENDS\,\,X} @@ -7486,8 +7488,9 @@ \section{Generics} \rationale{% A type parameter declaration like - \code{X\,\,\EXTENDS\,\,X} or \code{X\,\,\EXTENDS\,\,X?} or - \code{X\,\,\EXTENDS\,\,FutureOr} + \code{X\,\,\EXTENDS\,\,X} or + \code{X\,\,\EXTENDS\,\,FutureOr} 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\,\,\EXTENDS\,\,X} From 26bb31899d57eec0aa6fe418e8f2ede604ca7195 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 12 Aug 2026 13:36:19 +0000 Subject: [PATCH 12/12] WIP --- specification/dartLangSpec.tex | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specification/dartLangSpec.tex b/specification/dartLangSpec.tex index 246060781e..14f330450f 100644 --- a/specification/dartLangSpec.tex +++ b/specification/dartLangSpec.tex @@ -7477,25 +7477,25 @@ \section{Generics} has cyclic bounds. \commentary{% This prevents circular declarations like - \code{X\,\,\EXTENDS\,\,X} + \code{$X$\,\,\EXTENDS\,\,$X$} and - \code{X\,\,\EXTENDS\,\,Y, Y\,\,\EXTENDS\,\,X}. + \code{$X$\,\,\EXTENDS\,\,$Y$, $Y$\,\,\EXTENDS\,\,$X$}. It also prevents pseudo-circular declarations like - \code{X\,\,\EXTENDS\,\,X?} + \code{$X$\,\,\EXTENDS\,\,$X$?} and - \code{X\,\,\EXTENDS\,\,FutureOr, 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\,\,FutureOr} or - \code{X\,\,\EXTENDS\,\,X?} + \code{$X$\,\,\EXTENDS\,\,$X$} or + \code{$X$\,\,\EXTENDS\,\,FutureOr<$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\,\,\EXTENDS\,\,X} + \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}, + or a few other cases mainly involving bottom types and \code{Object}, which is not likely to be useful. We avoid these cycles and pseudo-cycles because they can introduce infinite loops into the computation of