Extend Shapes:: functions override to dynamic
Summary:
`Shapes::toDict` and `toArray` are magic. The HHI claims to return `dict<arraykey, mixed>` (or `darray`) but instead the argument itself is analyzed to return a dict of union of the keys of the shape and the union of the values of the shape. So, `Shapes::toDict($s)` where `$s: shape('a' => int)` will return `dict<string, int>`. If the type visitor does not determine a suitable result, the original result `dict<arraykey, mixed>` is returned.
For pessimization, I've made toDict always result in a like type even though for `dict<arraykey, mixed>` it's technically unnecessary. So, the default return type is `~dict<arraykey, mixed>`. The mapper also handles unions shape inputs and performs a simple transformation and union of the result.
Without pessimization, this is fine because the only legal inputs will be unions of shapes. However, with pessimization, we want to allow Shapes::toDict to take like shapes. Unfortunately, this results in the following flow:
- Given input type `~shape('a' => int)`
- Compute default return type: `~dict<arraykey, mixed>`.
- Decompose union of input:
- `dynamic` => no rule => return default type: `~dict<arraykey, mixed>`
- `shape('a' => int)` => follow shapes rule => return `~dict<string, int>`
- Union results: `(~dict<arraykey, mixed> | ~dict<string, int>)`
- Simplify unions, covariance yields: `~dict<arraykey, mixed>` as the final result.
Instead, I add a rule for dynamic, saying that `Shapes::toDict($d)` where `$d: dynamic` returns dynamic. Then, the final result in the above example is `~dict<string, int>`. **Note that `dynamic` is only a valid argument to `Shapes::toDict` when pessimization is enabled.**
# Alternative
This is a simpler alternative to another approach which is fetching the type variable that is substituted for T in
```
public static function toDict<T as shape(...)>(
T $shape
): dict<arraykey, mixed>;
```
after the coercion from `~shape('a' => int) ~> #1` and then doing a computation based off the type variable. This involves a heavier refactor of the shapes code.
Reviewed By: dlreeves
Differential Revision:
D18279781
fbshipit-source-id:
70cf66b81118b16e0c3e4e8f25b03df3120876b7