Avoid internal unification with any
Avoid internal unification with any

Summary:
On the whiteboard, we like to think about directional constraints, because
Flow is a type system that has subtyping. That is, given two object types,
`T = {p: X}` and `U = {p: Y}`, we say that `T < U` if `X < Y` and `Y < X`.

In practice, however, this can be very inefficient. As a critical performance
optimization, Flow also implements unification. In the above case, instead of
creating two constraints between `X` and `Y`, we can simply say that `X = Y`.

In the case where `X` is a tvar and `Y` is some resolved type, the unification
constraint has the effect of resolving `X` as well.

Unfortunately, there is a major wrinkle here, which is that unification and
`any` do not get along. Once a tvar becomes unified with `any`, it becomes
`any`, and we will not find any errors in constaints involving that tvar.

As a general principle, `X = Y` should behave the same as `X < Y && Y < X`, but
`any` does not live up to this principle.

This diff works to mitigate this issue, but does so only partially.

Before we try to unify a tvar with `any`, we first check whether we should.
This gives us the opportunity to tell Flow that we should not perform such a
unification, which is a capability we did not have before.

Why might we want to unify with `any`? There are several reasons:

1. Unifying bound tvars with declared types. We walk the AST in two phases; the
first creates tvars and builds up the environment (scopes, entries, etc), and
the second emits constraints. In the expression `var x: any = e`, the first
pass creates a tvar for `x` and the second pass unifies that tvar with `any`.

2. Resolving imported types. When we import a type, we create a tvar
representing the unknown type. Only in merge do we know what the resolved type
is. If that resolved type is `any`, the local type should also be.

3. BecomeT/UnifyT -- These operations are designed to actually resolve a tvar
to a given type. We should not break this contract with `any`.

4. Existentials. This is my least favorite misfeature in Flow, but preserving
any unification is inline with the original goal here. The existential tvar is
supposed to unify with whatever type runs into it first. For example, given a
function `f: (x: Box<*>) => void`, called with `Box<any>`, the `*` should
resolve to `any`.

5. Internal junk. There are a few places where we create tvars and then unify
them because we want the tvar to resolve. These should be changed to use
`resolve_id` directly.

Reviewed By: avikchaudhuri

Differential Revision: D6880880

fbshipit-source-id: ef34467d70dd1a6c763cb42f4e1e46572f318072

samwgoldman/flow,gabelevi/flow,JonathanUsername/flow,AgentME/flow,popham/flow,popham/flow,JonathanUsername/flow,claudiopro/flow,JonathanUsername/flow,gabelevi/flow,mroch/flow,samwgoldman/flow,nmote/flow,jamesgpearce/flow,mroch/flow,facebook/flow,JonathanUsername/flow,nmote/flow,popham/flow,mroch/flow,AgentME/flow,JonathanUsername/flow,popham/flow,nmote/flow,popham/flow,gabelevi/flow,jamesgpearce/flow,gabelevi/flow,facebook/flow,samwgoldman/flow,jamesgpearce/flow,claudiopro/flow,jamesgpearce/flow,jamesgpearce/flow,claudiopro/flow,facebook/flow,samwgoldman/flow,popham/flow,samwgoldman/flow,mroch/flow,mroch/flow,claudiopro/flow,gabelevi/flow,facebook/flow,JonathanUsername/flow,facebook/flow,JonathanUsername/flow,samwgoldman/flow,nmote/flow,AgentME/flow,mroch/flow,AgentME/flow,nmote/flow,jamesgpearce/flow,nmote/flow,gabelevi/flow,gabelevi/flow,jamesgpearce/flow,popham/flow,mroch/flow,claudiopro/flow,AgentME/flow,facebook/flow,samwgoldman/flow,nmote/flow,facebook/flow