Skip to content
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

Specify error for await e where the type of e has something to do with an extension type #3473

Closed
wants to merge 2 commits into from
Closed
Changes from all 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
16 changes: 14 additions & 2 deletions accepted/future-releases/extension-types/feature-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ information about the process, including in their change logs.
[1]: https://github.com/dart-lang/language/blob/master/working/1426-extension-types/feature-specification-views.md
[2]: https://github.com/dart-lang/language/blob/master/working/extension_structs/overview.md

2023.11.17
- Correct the rule about extension types and `await` expressions.

2023.10.31
- Simplify the rules about the relationship between extension types and the
types `Object` and `Object?`.
Expand Down Expand Up @@ -826,9 +829,18 @@ _is the extension type_
<code>V\<T<sub>1</sub>, .. T<sub>s</sub>&gt;</code>,
and that its static type _is an extension type_.

We say that an extension type is _unrelated to `Future`_ in the case where
it does not implement `Future<U>` for any `U` *(this means that it has no
direct or indirect superinterface of the form `Future<...>`)*.

It is a compile-time error if `await e` occurs, and the static type of
`e` is an extension type which is not a subtype of `Future<T>` for any
`T`.
`e` satisfiers at least one of the following criteria:

- an extension type which is unrelated to `Future`.
- a type of the form `T?` or `FutureOr<T>` where `T` is a type that matches
Copy link
Member

Choose a reason for hiding this comment

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

We think we should not include FutureOr<T> here. The type FutureOr<T> is very much releated to Future, even if T isn't. Actually, especially if T isnt.

You should be allowed to await FutureOr<Ext> where Ext is an extension type unrelated to Future.
We want to allow you to await FutureOr<T> for any T, because otherwise you'd have to do an (v is Future<T>) ? await v : v, which would be allowed and have all the same issues as what we are trying to avoid by disallowing it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, the point was that if you have an expression of type E which is an extension type that has no relation to Future then you can trivially type that same expression as FutureOr<E>, which we can think of as Future<E> | E, and then it seems contradictory if it's ok to await that, but it is not OK to await E` alone. So I classified all the unions including the "don't await me" type as "don't await me" as well.

We could drop this whole idea and say that (1) await just uses the extension type erasure, no matter what (also for computation of the type of await e), and (2) it's up to a lint to tell people that it's a violation of some notion of encapsulation to have this particular await expression.

one of the items in this list.
Copy link
Member

Choose a reason for hiding this comment

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

If we give the property of being in the list a name, then we can refer to it recursively here.

Say:

We say that a type `S` is *incompatible with `await`* if:
* `S` is an extension type which is unrelated to `Future`,
* `S` is `T?` and `T` is incompatible with `await`, or
* `S` is `T` bounded, where `T` is not `S`, and `T` is incompatible with `await`.

An expression `await e` is a compile-time error if the static type of `e` is incompatible with `await`.

(IIRC, a type is trivially bounded by itself, which I guess is why you use the "one of the earlier items" phrase to avoid infinite regress. I guess calling it a coinductive definition would allow the infinite recursion.)

- a type which is `T` bounded, where `T` matches one of the earlier items
*(this covers type variables and intersection types)*.

A compile-time error occurs if an extension type declares a member whose
basename is the basename of an instance member declared by `Object` as
Expand Down