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

Update flatten definition #2713

Merged
merged 7 commits into from
Dec 13, 2022
Merged

Conversation

eernstg
Copy link
Member

@eernstg eernstg commented Dec 11, 2022

The definition of flatten needed yet another revision in order to cover intersection types properly.

@eernstg eernstg requested review from lrhn and leafpetersen December 11, 2022 23:02
@github-actions
Copy link

github-actions bot commented Dec 11, 2022

Visit the preview URL for this PR (updated for commit 4f450ab):

https://dart-specification--pr2713-specify-flatten-inte-jhd4ajan.web.app

(expires Tue, 20 Dec 2022 17:13:14 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 6941ecd630c4f067ff3d02708a45ae0f0a42b88a

specification/dartLangSpec.tex Outdated Show resolved Hide resolved
specification/dartLangSpec.tex Outdated Show resolved Hide resolved
\item if $S$ has future type $U$
then \DefEquals{\flatten{T}}{\code{\flatten{U}}}.
\item otherwise,
\DefEquals{\flatten{T}}{\code{\flatten{X}}}.
Copy link
Member

Choose a reason for hiding this comment

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

... which falls back to case-analysis on the bound of X, which means we use the bound, even on a promoted type variable, if it's promoted to a non-future-value-having type.

I'd say \DefEquals{\flatten{T}}{\code{X}} to be consistent with what we have now.

Example:

  • Have <X extends FutureOr<Object?>> and X o = ...;
  • Promote o to X & Object by o is Object.
  • Do await o.
  • X&Object has no future value type, so we fall back on flatten(X)
  • X has future type Object?.
  • So await o, with o of type X & Object, has type Object?.

It's not unsound, because a result type of Object? never is, but I'm not absolutely sure it's what we want.
(Not entirely sure it isn't either. But I want to be sure either way.)

Copy link
Member Author

Choose a reason for hiding this comment

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

we fall back on flatten(X)

Yes flatten(X & Object) is flatten(X), because Object does not have a future type.

But X has future type FutureOr<Object?> so flatten(X) is Object?. So await o will await o and get the Object?, statically typed as Object?, which is sound.

I guess you're saying that if the developer tests explicitly for o is Object then we're supposed to forget that we know that anything-X is a Future<Object?> as well.

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.

specification/dartLangSpec.tex Outdated Show resolved Hide resolved
specification/dartLangSpec.tex Show resolved Hide resolved
or \code{FutureOr<$S$>?} bounded
then the future type of $T$ is \code{Future<$S$>?}
respectively \code{FutureOr<$S$>?}.
\item Otherwise, $T$ has no future type.
Copy link
Member

Choose a reason for hiding this comment

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

Does not seem to account for X? or (X & B)? (if that exists), because those are not bounded by anything but themselves (they are not type variables or promoted type variables, they just contain some, so the last two clauses of "is-S-bounded" do not apply), and they have no super-interfaces.

Maybe:

  • If T implements Future<S> for some S, T has future type Future<S>.
  • Otherwise, if T is FutureOr<S> for some S, T has future type Future<S>.
  • Otherwise, if T is B bounded for some B and B has future type F, so does T.
  • Otherwise, if T is R? and R has future type F, T has future type F?.
  • Otherwise T has no future type.

Copy link
Member Author

Choose a reason for hiding this comment

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

X? is handled by the first case in flatten, X? does not have a future type of its own.

(X & B)? cannot occur, intersection types are designed to be top-level only.

About the rulesets:

If T implements Future<S> for some S, T has future type Future<S>.

This is my first item.

Otherwise, if T is FutureOr<S> for some S, T has future type Future<S>.

This is different, but flatten would take those two different intermediate results to the same end result.

Otherwise, if T is B bounded for some B and B has future type F, so does T.

This is somewhat redundant: It may include a usage of the first item, but it would then already be covered by the first item.

Otherwise, if T is R? and R has future type F, T has future type F?.

I could use this to make the third item simpler, but it would only be applicable in some cases after having applied item 2.

Otherwise T has no future type.

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.

specification/dartLangSpec.tex Show resolved Hide resolved
specification/dartLangSpec.tex Outdated Show resolved Hide resolved
Copy link
Member Author

@eernstg eernstg left a comment

Choose a reason for hiding this comment

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

Remaining issue: Is it possible to express the future type of a type, or the definition of flatten, in a way which is more concise and more readable? Not quite sure. Looking at it.

specification/dartLangSpec.tex Show resolved Hide resolved
specification/dartLangSpec.tex Outdated Show resolved Hide resolved
specification/dartLangSpec.tex Outdated Show resolved Hide resolved
or \code{FutureOr<$S$>?} bounded
then the future type of $T$ is \code{Future<$S$>?}
respectively \code{FutureOr<$S$>?}.
\item Otherwise, $T$ has no future type.
Copy link
Member Author

Choose a reason for hiding this comment

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

X? is handled by the first case in flatten, X? does not have a future type of its own.

(X & B)? cannot occur, intersection types are designed to be top-level only.

About the rulesets:

If T implements Future<S> for some S, T has future type Future<S>.

This is my first item.

Otherwise, if T is FutureOr<S> for some S, T has future type Future<S>.

This is different, but flatten would take those two different intermediate results to the same end result.

Otherwise, if T is B bounded for some B and B has future type F, so does T.

This is somewhat redundant: It may include a usage of the first item, but it would then already be covered by the first item.

Otherwise, if T is R? and R has future type F, T has future type F?.

I could use this to make the third item simpler, but it would only be applicable in some cases after having applied item 2.

Otherwise T has no future type.

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.

\item if $S$ has future type $U$
then \DefEquals{\flatten{T}}{\code{\flatten{U}}}.
\item otherwise,
\DefEquals{\flatten{T}}{\code{\flatten{X}}}.
Copy link
Member Author

Choose a reason for hiding this comment

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

we fall back on flatten(X)

Yes flatten(X & Object) is flatten(X), because Object does not have a future type.

But X has future type FutureOr<Object?> so flatten(X) is Object?. So await o will await o and get the Object?, statically typed as Object?, which is sound.

I guess you're saying that if the developer tests explicitly for o is Object then we're supposed to forget that we know that anything-X is a Future<Object?> as well.

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.

specification/dartLangSpec.tex Show resolved Hide resolved
specification/dartLangSpec.tex Outdated Show resolved Hide resolved
specification/dartLangSpec.tex Outdated Show resolved Hide resolved
@eernstg eernstg merged commit 0cff768 into master Dec 13, 2022
@eernstg eernstg deleted the specify_flatten_intersection_dec22 branch December 13, 2022 17:25
@eernstg
Copy link
Member Author

eernstg commented Dec 13, 2022

@lrhn, I landed this. Let's take another iteration in a new PR, if needed.

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