Skip to content

ENH: Support slack variables (lower bound emulation) #2220

@randolf-scholz

Description

@randolf-scholz

Describe the Bug

Context: python/typing#674

Slack variables 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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions