facebook / facebook/pyrefly

ENH: Support slack variables (lower bound emulation)

Open
#2,220 3 comments 0 reactions 0 assignees View on GitHub
needs-discussion typechecking
Dominant language
Rust
Stars
7k
Forks
516
PR merge metrics
No merged PRs in 30d

Description

### Describe the Bug

Context: https://github.com/python/typing/issues/674

[Slack variables](https://en.wikipedia.org/wiki/Slack_variable) would allow us to emulate lower bounds on type variables, which is relevant for methods like `dict.__or__` or sequence concatenation, when an outer context is present.

```python
from typing import Never, assert_type, reveal_type

class Vec[T]: # invariant in T
def _items(self) -> list[T]: ...
def _append(self, item: T) -> None: ...

def concat_vecs[T1, T2, _T_slack=Never](
left: Vec[T1],
right: Vec[T2],
) -> Vec[T1 | T2 | _T_slack]: # <-- Slack variable makes return a supertype of T1 | T2
return Vec()

class A: ...
class B: ...
class C: ...

def test_vec_concat(left: Vec[A], right: Vec[B]) -> None:
# without outer context, the type is precise
assert_type(concat_vecs(left, right), Vec[A | B]) # ✅️
# outer context allows widening due to slack variables
_0: Vec[A | B] = concat_vecs(left, right) # ❌️
_1: Vec[A | B | C] = concat_vecs(left, right) # ❌️
_2: Vec[object] = concat_vecs(left, right) # ❌️
```

`pyrefly` fails to find existing solutions to these function calls:

- `_0`: (`T1=A`, `T2=B`, `_T_slack=Never`)
- `_1`: (`T1=A`, `T2=B`, `_T_slack=C`)
- `_2`: (`T1=A`, `T2=B`, `_T_slack=object`)

```
ERROR sandbox.py:21:38-42: Argument `Vec[A]` is not assignable to parameter `left` with type `Vec[A | B]` in function `concat_vecs`
ERROR sandbox.py:21:44-49: Argument `Vec[B]` is not assignable to parameter `right` with type `Vec[A | B]` in function `concat_vecs`
ERROR sandbox.py:22:38-42: Argument `Vec[A]` is not assignable to parameter `left` with type `Vec[A | B | C]` in function `concat_vecs`
ERROR sandbox.py:22:44-49: Argument `Vec[B]` is not assignable to parameter `right` with type `Vec[A | B | C]` in function `concat_vecs`
ERROR sandbox.py:23:38-42: Argument `Vec[A]` is not assignable to parameter `left` with type `Vec[object]` in function `concat_vecs`
```

### Sandbox Link

https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeS4ATrgLYAEALqcROgOZ0Q3G6UN0A5GADcYlADR1UcOGIYB9JsRiTKImKiiLmMADrp9AYyjS4dAGoxDAbQAqAXUR06AYk7phqShAz9WdW31nZ0wYMDp5CAYYGjgAClkoMABKOgBaAD46KAg4BjtHOkJioODQ8PlUYmUsBJgkySiYp1tUzMFcdBgnYsJ9fXK6Q07DVAVRQzg7AEZJWwAmSXlbeTgTQwBrAF4hUUp7ONLnWDAGJ0sbW2n7cSO6bzYACzOLKzt5m-02rIuZugAfALzAERFZrVCbQquOgAHjSaToAGV1hs6J5vKhsLA6DRUBt4PcYAwAK6UdBSOhwYnKPg6Oi4cJXEELO5qElk16GOLJfroYymOgAQR6JT5JhkdAAQiK%2BmKBQBhGW8wbRPLyCbyYZ8sZxE4vX6Cm73CBPfVvSX2b4dLqIO5uADuUUeuGJ-Bd0UoQ060XwDEkDEeMEYdNydGIakMuT05OCpjk2mUcS1o3GVnietUJueyUkBpBFtS0MAoOSAeD%2B7fTXWIvegffxNFBcPazI7QuhWBxMMSgwxcJSUWivD4sfA7vIAAznN6C-P2YLOLbVlPqtO6sJ%2B42m1JuQAy5GWY855NNJzZp4DJSD5bOF8mxsvJqvTpnN9Dd6P5sfrLhsAArKwMWfBNeIy3hM6Zrk%2B2YvnuIDiCArrQHAJDkIgIBuAAqgw0BRKQdBgMSfKYZ0cDKmEuG8LiCjoMSNDYGIcT4E4rAMFaeSULa%2B6Euy5JgLoIACNRtFsXQwD4AAvrx%2BgwSAZBqGAUCkIQPY0FAFBuAACqQsnyZSGA4AQ1aQGwpJjBAnSym4iIwEGzwMMQcCIAA9A5MlhPJhC8GwDkwOgDmYLgkwOVqhnGYRPlkZ6qCeNAmLYkFJohaZ5K4MQoWIfoZABp0aR7HAiV0AuvEAMyENMhUSegICibBEKYaIABi0AwBQaBYHgRBkJVQA

### (Only applicable for extension issues) IDE Information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.