Skip to content

Specify error for pseudo-cyclic type parameter bounds - #4743

Open
eernstg wants to merge 12 commits into
mainfrom
specify_433_aug26
Open

Specify error for pseudo-cyclic type parameter bounds#4743
eernstg wants to merge 12 commits into
mainfrom
specify_433_aug26

Conversation

@eernstg

@eernstg eernstg commented Aug 7, 2026

Copy link
Copy Markdown
Member

For background and discussion, please see #433.

This PR introduces a compile-time error for type parameters and their bounds when they form a union type based cycle. For example, not just X extends X and Y extends Z, Z extends Y are errors (as they have always been), but also X extends X? and Y extends FutureOr<Z>, Z extends Y. That is, we make it an error to form a cycle even when union types are stripped off first. This is done because it allows us to avoid some known sources of infinite looping in the subtype and standard upper bound algorithms.

Following #433 (comment), this PR also renames "union-free type derived from a type" to "union base type of a type".

@eernstg
eernstg requested a review from lrhn August 7, 2026 16:51
Comment thread specification/dart.sty Outdated
Comment thread specification/dartLangSpec.tex Outdated
Comment thread specification/dartLangSpec.tex Outdated
Comment thread specification/dartLangSpec.tex Outdated
Comment thread specification/dartLangSpec.tex Outdated
Comment thread specification/dartLangSpec.tex Outdated
\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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants