Fix computation of variance of generic type parameters occurring as roots of type...
commit3dd56a2be11b61cba3f6a28a96cdc081d8b2d8a5
authorSasha Manzyuk <manzyuk@fb.com>
Wed, 21 Aug 2019 09:29:11 +0000 (21 02:29 -0700)
committerHhvm Bot <hhvm-bot@users.noreply.github.com>
Wed, 21 Aug 2019 09:33:40 +0000 (21 02:33 -0700)
tree55509f94df5d45d85134e972103a7f9af74a6446
parenteafc93691184c201ab5a07f40f88531ccc161829
Fix computation of variance of generic type parameters occurring as roots of type accesses

Summary:
Previously we assumed that generic type parameters cannot occur in type accesses of the form `A::TB::TC`.  Here `A` is a type (e.g., a class) and `TB` and `TC` are type constant names.  We assumed that `A` couldn't be a generic type parameter.  And indeed, one cannot project type constants off of a generic as in
```
<?hh
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.

interface HasFoo {
  abstract const type TFoo;
  public function getFoo(): this::TFoo;
}

function test<T as HasFoo>(T $x): T::TFoo {
  return $x->getFoo();
}
```
This produces
```
T must be an identifier for a class, "self", or "this" (Naming[2061])
```
However, it **is** possible to use projections off of generics in `where` constraints, so the above can be written (a bit awkwardly) as follows:
```
<?hh
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.

interface HasFoo {
  abstract const type TFoo;
  public function getFoo(): this::TFoo;
}

function test<T as HasFoo, TFoo>(T $x): TFoo where TFoo = T::TFoo {
  return $x->getFoo();
}
```
This example type checks but produces a lint warning about a redundant generic `T`.  This is because we fail to account for the occurrence of `T` in the type `T::TFoo` inside the `where` constraint.

Reviewed By: kmeht

Differential Revision: D16916838

fbshipit-source-id: fabec480222e37453b7d02f027103746c9efcb10
hphp/hack/src/typing/typing_variance.ml