Flow: Invalid `type is incompatible with some instantiation of` errors

Created on 6 May 2016  路  6Comments  路  Source: facebook/flow

This is as far as I was able to reduce a test case:

/* @flow */

declare class Clip <a> {};
declare function createClip <a> ():Clip<a>;

class Lens <from, to> {
  get: (input:from) => to;
  set: (input:from, value:to) => from;
  constructor(get:(input:from) => to, set:(input:from, value:to) => from) {
    this.get = get;
    this.set = set;
  }
}

class Model <a> {
  clip: Clip<a>;
  constructor(clip:Clip<a>) {
    this.clip = clip
  }
  set <inner> (lens:Lens<Model<a>, inner>, value:inner):Model<a> {
    return lens.set(this, value)
  }
}


export const startRecording = <a>
  (model:Model<a>, value:Clip<a>=createClip()):Model<a> =>
  model.set(clip, value)

const clip = new Lens
  ( model => model.clip
  , (model, clip) =>
    new Model(clip)
  )

It produces following errors:

scratch.js:26
 26: export const startRecording = <a>
                                    ^ a. This type is incompatible with
 26: export const startRecording = <a>
                                   ^ some incompatible instantiation of `a`


Found 1 error

What is also interesting that if code is modified to avoid default parameter it seems to no longer error:

/* @flow */

declare class Clip <a> {};
declare function createClip <a> ():Clip<a>;

class Lens <from, to> {
  get: (input:from) => to;
  set: (input:from, value:to) => from;
  constructor(get:(input:from) => to, set:(input:from, value:to) => from) {
    this.get = get;
    this.set = set;
  }
}

class Model <a> {
  clip: Clip<a>;
  constructor(clip:Clip<a>) {
    this.clip = clip
  }
  set <inner> (lens:Lens<Model<a>, inner>, value:inner):Model<a> {
    return lens.set(this, value)
  }
}


export const startRecording = <a>
  (model:Model<a>):Model<a> =>
  model.set(clip, createClip())

const clip = new Lens
  ( model => model.clip
  , (model, clip) =>
    new Model(clip)
  )
polymorphism

Most helpful comment

It would tremendously help debugging (for me, at least) to print an example of an instantiation that would be invalid, rather than just some invalid instantiation of <type>.

All 6 comments

Another very interesting observation is that if clip Lens is used directly flow will error regardless if call to createClip() is inlined or used a default arg value:

/* @flow */

declare class Clip <a> {};
declare function createClip <a> ():Clip<a>;

class Lens <from, to> {
  get: (input:from) => to;
  set: (input:from, value:to) => from;
  constructor(get:(input:from) => to, set:(input:from, value:to) => from) {
    this.get = get;
    this.set = set;
  }
}

class Model <a> {
  clip: Clip<a>;
  constructor(clip:Clip<a>) {
    this.clip = clip
  }
  set <inner> (lens:Lens<Model<a>, inner>, value:inner):Model<a> {
    return lens.set(this, value)
  }
}


export const startRecording = <a>
  (model:Model<a>):Model<a> =>
  clip.set(model, createClip())

const clip = new Lens
  ( model => model.clip
  , (model, clip) =>
    new Model(clip)
  )

this is a different variation of the same issue that I can't even make sense of:

/* @flow */

declare class Clip <a> {
  static write(clip:Clip<a>):Clip<a>
};

class Lens <from, to> {
  get: (input:from) => to;
  set: (input:from, value:to) => from;
  constructor(get:(input:from) => to, set:(input:from, value:to) => from) {
    this.get = get;
    this.set = set;
  }
}

class Model <a> {
  clip: ?Clip<a>;
  constructor(clip:?Clip<a>) {
    this.clip = clip
  }
}

const clip = new Lens
  ( model => model.clip
  , (model, clip) =>
    new Model(clip)
  )

const write = <a>
  (model:Model<a>) =>
  ( model.clip == null
  ? model
  : clip.set(model, Clip.write(model.clip))
  )

Produces

scratch.js:29
 29: const write = <a>
                    ^ a. This type is incompatible with
 29: const write = <a>
                   ^ some incompatible instantiation of `a`


Found 1 error

I get a similar error for the following construction:

export interface OptionPattern<T, X> {
  none: () => X;
  some: (t: T) => X;
}

function some<T>(t: T): <X>(pattern: OptionPattern<T, X>) => X {
  return pattern => pattern.some(t);
}
 14:   return pattern => pattern.some(t);
                         ^^^^^^^^^^^^^^^ call of method `some`
 14:   return pattern => pattern.some(t);
                         ^^^^^^^^^^^^^^^ X. This type is incompatible with the expected return type of
 14:   return pattern => pattern.some(t);
              ^^^^^^^^^^^^^^^^^^^^^^^^^^ some incompatible instantiation of `X`

I also get a very similar error for this code:

/* @flow */

class C<X> {
  x: X;

  getFunc(x: X) {
    this.x = x;
    return (x2: X) => x2;
  }
}

const c: C<number> = new C();
c.getFunc(1)(1); // this incorrectly errors on the subsequent function invocation

which yields these errors:

 13: c.getFunc(1)(1); // this incorrectly errors on the subsequent function invocation
     ^^^^^^^^^^^^^^^ function call
 13: c.getFunc(1)(1); // this incorrectly errors on the subsequent function invocation
                  ^ number. This type is incompatible with
  8:     return (x2: X) => x2;
                     ^ some incompatible instantiation of `X`

I've managed to get quite a few variations on the same theme, but for me all issues were related to the me trying to share the closed type definitions within the parent class within either a child class or an internal function.

I received this error after I used a nested union of string literals as the bound for a generic type parameter; I had:

type XY = 'x' | 'y';
type WH = 'width' | 'height';
declare function swapDimensions<T :XY|WH>(input: T) :T;

In my mind that meant that x or y could only result in x or y and width or height could only result in width or height -- however the fallacy is that any intermediate type XY really exists. The generic clause will be expanded to <T :'x' | 'y' | 'width' | 'height'>. Now if you read it it is clear that this function can never return anything other than the exact string it is passed.

It would tremendously help debugging (for me, at least) to print an example of an instantiation that would be invalid, rather than just some invalid instantiation of <type>.

Was this page helpful?
0 / 5 - 0 ratings