Flow: type is incompatible with some incompatible instantiation

Created on 4 Nov 2015  路  6Comments  路  Source: facebook/flow

Following code does not type check:

/* @flow */

type F = <a> (input:a) => a
const double:F = x => x * 2

It errors as follows:

src/flowing.js:4
  4: const double:F = x => x * 2
                           ^ a. This type is incompatible with
  4: const double:F = x => x * 2
                           ^^^^^ number

src/flowing.js:4
  4: const double:F = x => x * 2
                           ^^^^^ number. This type is incompatible with
  4: const double:F = x => x * 2
                      ^^^^^^^^^^ some incompatible instantiation of a


Found 2 errors

I would expect flow to infer implementation of double and refine it's type to be a bound version of claimed F or more specifically it to be <a:number> (x:a) => a rather than error as it does now.

I can also get behind the idea that flow should not bind polymorphic types by inferring double since author claimed it's type to be F. Although in that case user should be allowed to annotate double with a bound version of F.

/* @flow */

type F = <a> (input:a) => a
const double:F<number> = x => x * 2

But flow does not allow that either instead it fails with following errors:

src/flowing.js:4
  4: const double:F<number> = x => x * 2
                  ^^^^^^^^^ type application of identifier `F`. Expected polymorphic type instead of
  4: const double:F<number> = x => x * 2
                  ^^^^^^^^^ type `F`

src/flowing.js:4
  4: const double:F<number> = x => x * 2
                              ^^^^^^^^^^ arrow function. Expected polymorphic type instead of
  4: const double:F<number> = x => x * 2
                  ^^^^^^^^^ type `F`


Found 2 errors

P.S.: This example is convoluted but that's so that it can be short & simple.

Most helpful comment

Seconded. @samwgoldman, It would be really helpful if you could go into a little bit more detail about your description of why this is valid error? I re-read your paragraph in the other issue about 20 times, and I still can't make sense of it. Or, is there maybe another resource I can seek out for some more context?

All 6 comments

I think this is the same as #856. At least, my explanation for why this is a non-issue is the same.

Also, if you actually want to parameterize the type of F, you can, you just need to move the parameterization back into the type alias. type F<T> = (x: T) => T, then double: F<number> = x => x*2 should type check.

I think I answered this completely.

Is there a workaround that doesn't involve declaring a separate type for every function?

I encountered this problem while writing this function:

async function resolveIgnoreErrors<T>(promise: Promise<T>): ?T {
  try {
    return await promise;
  } catch (e) {
    return null;
  }
}

I was pretty surprised to see an error, and despite reading your comments on this and #856, I don't understand why it's happening, nor why the workaround helps.

 13:     return await promise;
         ^^^^^^^^^^^^^^^^^^^^^ Promise. This type is incompatible with the expected return type of
     v---------------------------------------------------------------
 11: async function resolveIgnoreErrors<T>(promise: Promise<T>): ?T {
 12:   try {
 13:     return await promise;
...:
 18: }
     ^ some incompatible instantiation of `T`

Seconded. @samwgoldman, It would be really helpful if you could go into a little bit more detail about your description of why this is valid error? I re-read your paragraph in the other issue about 20 times, and I still can't make sense of it. Or, is there maybe another resource I can seek out for some more context?

@keithkml async functions are returning Promise objects, so the signature should be async function resolveIgnoreErrors<T>(p: Promise<T>): Promise<?T>.

if you leave the return type as ?T, then returning null is actually Promise<null>, which might be not compatible with T (eg. when T is number, you can only return ?number, and Promise<null> is definitely not number).

The error message, in this case, is cryptic, flow should report that async functions must return promises.

Was this page helpful?
0 / 5 - 0 ratings