Skip to content

Ternary conditional operator does not resolve type properly #2577

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

Closed
yanqui-uxo opened this issue Oct 18, 2022 · 5 comments
Closed

Ternary conditional operator does not resolve type properly #2577

yanqui-uxo opened this issue Oct 18, 2022 · 5 comments
Labels
least-upper-bound Proposals about improvements of the LUB algorithm

Comments

@yanqui-uxo
Copy link

yanqui-uxo commented Oct 18, 2022

This yields the error A value of type "Object" can't be returned from the function 'func' because it has a return type of 'B'.. This error does not occur using regular conditional syntax (if/else). I am using Dart 2.18.2, and this can be replicated on DartPad.

class A {}

class B {}

class C extends A implements B {}

class D extends A implements B {}

B func(bool b) => b ? C() : D();
@yanqui-uxo yanqui-uxo changed the title Ternary operator does not resolve type properly Ternary conditional operator does not resolve type properly Oct 18, 2022
@srawlins
Copy link
Member

Duplicate of #1904 and #1877 and similar to #2216

@srawlins
Copy link
Member

This example is different from others in that it does not even require generics 😢 . The issue here comes from the combination of extends and implements in C and D. Removing extends A in either C or D fixes the issue. Removing implements B in either C or D (and changing the func return to B) fixes the issue.

@lrhn
Copy link
Member

lrhn commented Oct 19, 2022

The cause of the issue here is that C and D does not have any least upper bound in the type lattice. It has two minimal upper bounds, A and B, but neither is special, and picking either of them would be arbitrary.
The two types are completely symmetric. We could choose to give preference to the extends type over the implements type, but that too would be arbitrary (and easily foiled by changing D to class D extends B implements A {}, or make both superinterfaces come from implements).

In case of such an ambiguity, the least-upper-bound algorithm gives up on those types, and here it then finds Object.

The real issue is that we dont use the context type information to help disambiguate. We have available information that could help us, we just don't use it.

@caseycrogers
Copy link

caseycrogers commented Sep 7, 2023

This is also a problem (unsurprisingly) with switch expressions:
B func(bool b) => switch (b) { true => C(), false => D(), };

Is there any potential for fixing this? eg bias towards the type declared in the function signature (or variable declaration, if applicable)?

While this is pretty niche, as far as I can tell there's no way to write this logic in a compile-time safe manner so it seems like a pretty unfortunate limitation.

@eernstg eernstg added the least-upper-bound Proposals about improvements of the LUB algorithm label Sep 7, 2023
@munificent
Copy link
Member

This is also a problem (unsurprisingly) with switch expressions: B func(bool b) => switch (b) { true => C(), false => D(), };

Yes, definitely. Switch expressions have made least upper bound a bigger pain point than it already was.

Is there any potential for fixing this? eg bias towards the type declared in the function signature (or variable declaration, if applicable)?

Yes, I think we're leaning towards using the context type as a hint to least upper bound. The tracking issue for that is #1618. I'll close this one in favor of that.

While this is pretty niche, as far as I can tell there's no way to write this logic in a compile-time safe manner so it seems like a pretty unfortunate limitation.

You can always just upcast. Since it's an upcast, it will never fail. Having to upcast is annoying though, since it's hard to tell if a given cast is casting up (safe) or down (may fail at runtime).

@munificent munificent closed this as not planned Won't fix, can't repro, duplicate, stale Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
least-upper-bound Proposals about improvements of the LUB algorithm
Projects
None yet
Development

No branches or pull requests

6 participants