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

    needs-discussionAn issue where it's not clear whether there is a bug or we are behaving as expected.typechecking

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions