Simplify and improve type accesses through intersections and unions
Summary:
Improve the expressivity of type constant access through intersections. Currently, the following code is rejected:
```
interface IBoundedJ {
abstract const type TP as J;
public function get():this::TP;
}
interface IBoundedK {
abstract const type TP as K;
}
function test3<T as (IBoundedJ & IBoundedK)>(T $x):(J & K) {
return $x->get();
}
```
It's safe to accept, if we merge the bounds on `TP` when projecting from `(IBoundedJ & IBoundedK)`.
Although this example uses the experimental intersection type syntax, the same effect will happen for multiple bounds on generics, and type refinements.
We also tighten up the code a bit, rejecting all kinds of projections through unions, unless accessing non-abstract type constants.
Reviewed By: vsiles
Differential Revision:
D25615483
fbshipit-source-id:
e3540807529a6ba22cc90763bef53c554a40af7e