facebook / flow

Adds static typing to JavaScript to improve developer productivity and code quality.
https://flow.org/
MIT License
22.08k stars 1.85k forks source link

Premature incompatibily errors in generic classes definitions #3711

Open Gozala opened 7 years ago

Gozala commented 7 years ago

Here is simplified example:

class Task <x, a> {
  static spawn: <b> (task:Task<empty, b>) => Task<empty, b>
  spawn <b> ():Task<empty, b> {
    return Task.spawn(this)
  }
}

Here flow reports following error:

  6:     return Task.spawn(this)
                ^^^^^^^^^^^^^^^^ call of method `spawn`
  3: class Task <x, a> {
                 ^ x. This type is incompatible with
  4:   static spawn: <a, b> (task:Task<empty, a>) => Task<empty, b>
                                       ^^^^^ empty

What I actually expect is for flow to report type error when task.spawn() is called on tasks that can fail (Task<error, value>) and report no errors when called on tasks that can not fail (Task<empty, value>).

Gozala commented 7 years ago

To be more clear this is a behavior I'm aiming for:

/* @flow */

class Task <x, a> {
  static succeed: <x, a> (value:a) => Task<x, a>
  static fail: <x, a> (error:x) => Task<x, a>
  static spawn: <a, b> (task:Task<empty, a>) => Task<empty, b>
}

Task.spawn(Task.succeed(4))
Task.spawn(Task.fail(4))

Which fails if failing task is spawn, but does not fail if succeeding task is spawn:

    10: Task.spawn(Task.fail(4))
                             ^ number. This type is incompatible with
    6:   static spawn: <a, b> (task:Task<empty, a>) => Task<empty, b>
                                         ^ empty

I just want to enable calling spawn as a method rather than static function.