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

Conditional type only works if I inline it #9107

Closed
mwiencek opened this issue Nov 26, 2023 · 5 comments
Closed

Conditional type only works if I inline it #9107

mwiencek opened this issue Nov 26, 2023 · 5 comments
Labels

Comments

@mwiencek
Copy link

Flow version: 0.222.0

I couldn't figure out why Flow is giving an error and inferring number here. (Sorry for the all the code; I tried to minimize it as much as I could. The intent of the set function is in the comment at the bottom: supposed to be equivalent to d[0].year = 1988).

At first I thought I made a typo somewhere, but after a couple hours playing with the code (:cry:), I found out the error goes away if I inline some of the conditional types.

In case it's not clear, I only changed the following in the type parameters of the set function overloads:

-K2: KeyType2<T, K1>
+K2: PropType<T, K1> extends $ReadOnlyArray<mixed> ? number : PropType<T, K1> extends {...} ? $Keys<PropType<T, K1>

which essentially expands the KeyType2 definition in-place.

I was hoping for a way to do all of this without overloads to begin with, but alas, my best attempt did not work.

@mwiencek
Copy link
Author

mwiencek commented Nov 26, 2023

I don't have to expand it within the set type parameters; it also works if expand it in the KeyType2 definition:

-type KeyType2<+T, +K1> = KeyType<PropType<T, K1>>;
+type KeyType2<+T, +K1> = PropType<T, K1> extends $ReadOnlyArray<mixed> ? number : PropType<T, K1> extends {...} ? $Keys<PropType<T, K1>> : empty;

Edit: Also, weirdly, if I revert all the inlining and just do ('year': KeyType2<DatePeriods, 0>);, then that type-checks fine. So it works in some cases, but not in the set function.

@SamChou19815
Copy link
Contributor

The behavior seems expected to me. number is coming from KeyType<DatePeriods>. Conditional type is order sensitive. If you switch the order of two conditions in KeyType, it would work

@mwiencek
Copy link
Author

mwiencek commented Nov 27, 2023

@SamChou19815 Thanks for the pointer, but not sure I follow: in the expanded version the order of the conditions is the same, isn't it?

The error message suggests that K2: KeyType2<T, K1> should be number, but K1 is KeyType<DatePeriods>, which is also number. Indeed this works fine:

type KeyType2<+T, +K1> = KeyType<PropType<T, K1>>;

('year': KeyType2<DatePeriods, KeyType<DatePeriods>>);

@SamChou19815 SamChou19815 reopened this Nov 27, 2023
@SamChou19815
Copy link
Contributor

I have a smaller repro here.

@mwiencek
Copy link
Author

@SamChou19815 Thanks for the fix!

facebook-github-bot pushed a commit that referenced this issue Nov 29, 2023
…itional type

Summary:
When we have unresolved inputs into conditional type during implicit instantiation, we will just produce a placeholder type (a variant of any) to signal that we don't know what the result is, so we will just put up the most permissive type possible, but doesn't make it contribute to solutions of implicit instantiation.

Placeholders are tricky to get right. In particular, we need to ensure that it doesn't leak. In hint decomposition, we will fail it if the final result contains placeholder. However, here in conditional type, we are not very careful so the effect leaked.

In the added test, we have two nested conditional type. During solve_targs of implicit instantiation, we will receive unresolved tvar from `T` and `K`. When we are evaluating `PropType`, we correctly produced a placeholder as a result. But then, the placeholder any propagated to the evaluation of `KeyType`, causing the true branch to be taken, but we should still refuse to evaluate it and return placeholder, so that we remain permissive and don't error, and the actual evaluation is deferred to instantiation with solution stage. However, since we picked the true branch, we will error, and speculation will fail on both branches, which leads to the confusing error in the GitHub issue.

The fix is fairly simple. We will defend against both unresolved inputs and placeholder inputs. In both cases, we don't know which branch to take, so we should produce placeholder. Placeholder in, placeholder out.

Close #9107.

Changelog: [fix] We fixed an issue that will cause some nested conditional type to be evaluated to any. (Example: Issue #9107)

Reviewed By: panagosg7

Differential Revision:
D51644844

------------------------------------------------------------------------
(from 3f9d5c274d933030493888532a5e24c30b6d882e)

fbshipit-source-id: 958bb5d2d37185b78f239cdd7bb70a69ae1498a4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants