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

Fixes #2490. Add more await tests for extension types #2500

Merged
merged 5 commits into from
Jan 29, 2024

Conversation

sgrekhov
Copy link
Contributor

No description provided.

Copy link
Member

@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.

Looks good! A few tests have issues, though, in particular with intersection types.

Copy link
Contributor Author

@sgrekhov sgrekhov left a comment

Choose a reason for hiding this comment

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

Updated. Please take another look

extension type IntET(int _) {}

test1<X extends FutureOr<NumET>>(X x) async {
if (x is int) {
Copy link
Member

Choose a reason for hiding this comment

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

I think this would have to be something like x is NumET: We don't get a promotion of x to a non-subtype of FutureOr<NumET>, and then we aren't testing anything of the form X & B.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to

extension type NumET(num _) implements num {}
extension type IntET(int _) implements NumET {}

This should work, shouldn't it?

Copy link
Member

Choose a reason for hiding this comment

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

Not yet: The type of x is initially X extends FutureOr<NumET>. We then test for int, but int is not a subtype of FutureOr<NumET> and hence there's no promotion and no intersection type.

However, NumET <: FutureOr<NumET> because T <: FutureOr<T> for any T (including extension types), so we could have if (x is NumET) ... and that would promote the type of x to X & NumET. Similarly, we could have if (x is IntET) ... if we have IntET <: NumET (as in the new code).

NumET and IntET are incompatible with await, but that's OK: If we await x then we just determine that NumET/IntET do not derive a future type, but X does, and then await x is OK, with type flatten(X) == flatten(FutureOr<NumET>) == NumET.

Copy link
Contributor Author

@sgrekhov sgrekhov Jan 29, 2024

Choose a reason for hiding this comment

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

NumET and IntET are incompatible with await, but that's OK: If we await x then we just determine that NumET/IntET do not derive a future type, but X does, and then await x is OK, with type flatten(X) == flatten(FutureOr<NumET>) == NumET.

Sorry, I don't quite understand. Do you want to sat that

if (x is IntET) {
  await x;
}

is OK? No error? But, according to the definition

  • T is X & B, and either:
    • B is incompatible with await, or

In case of x is IntET, IntET is incompatible with await, criteria met, so await x should be a compile-time error.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, you're right. We have a slight inconsistency because 'incompatible with await' is more aggressive than flatten, so we never get around to try to invoke flatten on the type of x because it is already an error, as you mention, according to the 'incompatible' rule to have await x.

The underlying question is "do we want to make it an error to have await e when the type of e is X & B where B 'is bad' but X is 'good'?". The 'incompatible' rule says "yes, don't even bother to look at X", but flatten allows us to disregard B if it doesn't derive any future types, and then use X.

So the question is whether we can actually have this situation at all:

  • We do await x.
  • The static type of x is X & B.
  • B is an extension type which is compatible with await.
  • B does not derive a future type.
  • So we use X in flatten, and it does derive a future type.

I don't think we can find a type B with those properties.

So this basically means that we can't use the 'otherwise' case in the rule about flatten on an intersection type X & B where B is an extension type.

But then we'd just have to test that we do get the compile-time error when B is an extension type that does not implement Future<T> for any T. Perhaps that's already done in some other test?

Next, we can test that the first case is used in the flatten rule about X & B when X does not derive a future type, but B does (perhaps X extends Object and B == NumFutureET).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But then we'd just have to test that we do get the compile-time error when B is an extension type that does not implement Future<T> for any T. Perhaps that's already done in some other test?

Below in this test we have if (x is IntET) {

Next, we can test that the first case is used in the flatten rule about X & B when X does not derive a future type, but B does (perhaps X extends Object and B == NumFutureET).

Added static_analysis_extension_types_A08_t11.dart which checks it. In case X extends Object X is compatible with await, so I used X extends ObjectET

Copy link
Member

@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.

Still a couple of issues. I've commented on several cases where the description is about intersection types, but we don't have an expression whose type is an intersection type. In general, we just need to perform the type test on a subtype of the current type of the variable at that point.

Copy link
Contributor Author

@sgrekhov sgrekhov left a comment

Choose a reason for hiding this comment

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

Updated. Please review, there are some places where I'm not 100% sure

extension type IntET(int _) {}

test1<X extends FutureOr<NumET>>(X x) async {
if (x is int) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to

extension type NumET(num _) implements num {}
extension type IntET(int _) implements NumET {}

This should work, shouldn't it?

Copy link
Member

@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.

This one still has some issues.

extension type IntET(int _) {}

test1<X extends FutureOr<NumET>>(X x) async {
if (x is int) {
Copy link
Member

Choose a reason for hiding this comment

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

Not yet: The type of x is initially X extends FutureOr<NumET>. We then test for int, but int is not a subtype of FutureOr<NumET> and hence there's no promotion and no intersection type.

However, NumET <: FutureOr<NumET> because T <: FutureOr<T> for any T (including extension types), so we could have if (x is NumET) ... and that would promote the type of x to X & NumET. Similarly, we could have if (x is IntET) ... if we have IntET <: NumET (as in the new code).

NumET and IntET are incompatible with await, but that's OK: If we await x then we just determine that NumET/IntET do not derive a future type, but X does, and then await x is OK, with type flatten(X) == flatten(FutureOr<NumET>) == NumET.


test1<X extends Future<NumET>>(X x) async {
test1<X extends NumET>(X x) async {
if (x is int) {
Copy link
Member

Choose a reason for hiding this comment

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

We still can't promote to int, because that isn't a subtype of NumET.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed... Removed this

if (x is int) {
await x; // No error here, int is compatible with await
}
if (x is FutureOr<IntET>) {
Copy link
Member

Choose a reason for hiding this comment

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

Can't promote to FutureOr<IntET>.

if (x is int) {
await x; // No error here, int is compatible with await
}
if (x is FutureOr<IntET>) {
Copy link
Member

Choose a reason for hiding this comment

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

Can't promote x because FutureOr<IntET> is not a subtype of num.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Copy link
Member

@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.

Added a comment.

extension type IntET(int _) {}

test1<X extends FutureOr<NumET>>(X x) async {
if (x is int) {
Copy link
Member

Choose a reason for hiding this comment

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

Ah, you're right. We have a slight inconsistency because 'incompatible with await' is more aggressive than flatten, so we never get around to try to invoke flatten on the type of x because it is already an error, as you mention, according to the 'incompatible' rule to have await x.

The underlying question is "do we want to make it an error to have await e when the type of e is X & B where B 'is bad' but X is 'good'?". The 'incompatible' rule says "yes, don't even bother to look at X", but flatten allows us to disregard B if it doesn't derive any future types, and then use X.

So the question is whether we can actually have this situation at all:

  • We do await x.
  • The static type of x is X & B.
  • B is an extension type which is compatible with await.
  • B does not derive a future type.
  • So we use X in flatten, and it does derive a future type.

I don't think we can find a type B with those properties.

So this basically means that we can't use the 'otherwise' case in the rule about flatten on an intersection type X & B where B is an extension type.

But then we'd just have to test that we do get the compile-time error when B is an extension type that does not implement Future<T> for any T. Perhaps that's already done in some other test?

Next, we can test that the first case is used in the flatten rule about X & B when X does not derive a future type, but B does (perhaps X extends Object and B == NumFutureET).

Copy link
Contributor Author

@sgrekhov sgrekhov left a comment

Choose a reason for hiding this comment

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

Thank you! Updated once again. Please review


test1<X extends Future<NumET>>(X x) async {
test1<X extends NumET>(X x) async {
if (x is int) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed... Removed this

extension type IntET(int _) {}

test1<X extends FutureOr<NumET>>(X x) async {
if (x is int) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

But then we'd just have to test that we do get the compile-time error when B is an extension type that does not implement Future<T> for any T. Perhaps that's already done in some other test?

Below in this test we have if (x is IntET) {

Next, we can test that the first case is used in the flatten rule about X & B when X does not derive a future type, but B does (perhaps X extends Object and B == NumFutureET).

Added static_analysis_extension_types_A08_t11.dart which checks it. In case X extends Object X is compatible with await, so I used X extends ObjectET

if (x is int) {
await x; // No error here, int is compatible with await
}
if (x is FutureOr<IntET>) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

@sgrekhov sgrekhov requested a review from eernstg January 29, 2024 11:23
Copy link
Member

@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.

Just one more thing: I think there is still one ? that prevents promotion.

Copy link
Member

@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.

LGTM!

@eernstg eernstg merged commit a38a448 into dart-lang:master Jan 29, 2024
2 checks passed
copybara-service bot pushed a commit to dart-lang/sdk that referenced this pull request Feb 5, 2024
2024-02-02 sgrekhov22@gmail.com Fix dart-lang/co19#2517. Fix wrong test, add experimental flags (dart-lang/co19#2518)
2024-02-02 sgrekhov22@gmail.com Fix dart-lang/co19#2490. Update incompatible with await tests according to the changed rule (dart-lang/co19#2516)
2024-02-01 sgrekhov22@gmail.com dart-lang/co19#2420. Add more exhaustiveness tests (dart-lang/co19#2513)
2024-01-31 sgrekhov22@gmail.com dart-lang/co19#2446. Add additional test for cast pattern (dart-lang/co19#2514)
2024-01-30 sgrekhov22@gmail.com dart-lang/co19#1399. Add more tests for records (dart-lang/co19#2511)
2024-01-30 sgrekhov22@gmail.com dart-lang/co19#2485. Update map and list constant literals tests. Add parenthesized for records (dart-lang/co19#2512)
2024-01-29 sgrekhov22@gmail.com Fixes dart-lang/co19#2490. Add more await tests for extension types (dart-lang/co19#2500)
2024-01-29 sgrekhov22@gmail.com dart-lang/co19#2119. Fix typo in Subtyping tests description (dart-lang/co19#2510)
2024-01-29 sgrekhov22@gmail.com Fixes dart-lang/co19#2505. Add more tests for `call` member (dart-lang/co19#2506)
2024-01-29 sgrekhov22@gmail.com dart-lang/co19#2420. Add cast-pattern tests for extension types (dart-lang/co19#2458)

Change-Id: I631705a013f9a77910ae0f0be5a9fea01e7c719f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/350240
Reviewed-by: Erik Ernst <eernst@google.com>
Commit-Queue: Erik Ernst <eernst@google.com>
Reviewed-by: William Hesse <whesse@google.com>
sgrekhov added a commit to sgrekhov/co19 that referenced this pull request Feb 15, 2024
sgrekhov added a commit to sgrekhov/co19 that referenced this pull request Feb 15, 2024
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.

None yet

2 participants