# Assignable-to relation

```toml
[environment]
python-version = "3.12"
```

The `is_assignable_to(S, T)` relation below checks if type `S` is assignable to type `T` (target).
This allows us to check if a type `S` can be used in a context where a type `T` is expected
(function arguments, variable assignments). See the [typing documentation] for a precise definition
of this concept.

## Basic types

### Fully static

Fully static types participate in subtyping. If a type `S` is a subtype of `T`, `S` will also be
assignable to `T`. Two equivalent types are subtypes of each other:

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

class Parent: ...
class Child1(Parent): ...
class Child2(Parent): ...
class Grandchild(Child1, Child2): ...
class Unrelated: ...

static_assert(is_assignable_to(int, int))
static_assert(is_assignable_to(Parent, Parent))
static_assert(is_assignable_to(Child1, Parent))
static_assert(is_assignable_to(Grandchild, Parent))
static_assert(is_assignable_to(Unrelated, Unrelated))

static_assert(not is_assignable_to(str, int))
static_assert(not is_assignable_to(object, int))
static_assert(not is_assignable_to(Parent, Child1))
static_assert(not is_assignable_to(Unrelated, Parent))
static_assert(not is_assignable_to(Child1, Child2))
```

### Gradual types

The dynamic type is assignable to or from any type.

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing import Any, Literal

static_assert(is_assignable_to(Unknown, Literal[1]))
static_assert(is_assignable_to(Any, Literal[1]))
static_assert(is_assignable_to(Literal[1], Unknown))
static_assert(is_assignable_to(Literal[1], Any))
```

## Literal types

### Boolean literals

`Literal[True]` and `Literal[False]` are both subtypes of (and therefore assignable to) `bool`,
which is in turn a subtype of `int`:

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Literal

static_assert(is_assignable_to(Literal[True], Literal[True]))
static_assert(is_assignable_to(Literal[True], bool))
static_assert(is_assignable_to(Literal[True], int))

static_assert(not is_assignable_to(Literal[True], Literal[False]))
static_assert(not is_assignable_to(bool, Literal[True]))
```

### Integer literals

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Literal

static_assert(is_assignable_to(Literal[1], Literal[1]))
static_assert(is_assignable_to(Literal[1], int))

static_assert(not is_assignable_to(Literal[1], Literal[2]))
static_assert(not is_assignable_to(int, Literal[1]))
static_assert(not is_assignable_to(Literal[1], str))
```

### String literals and `LiteralString`

All string-literal types are subtypes of (and therefore assignable to) `LiteralString`, which is in
turn a subtype of `str`:

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing_extensions import Literal, LiteralString
from typing import Sequence, Any

static_assert(is_assignable_to(Literal["foo"], Literal["foo"]))
static_assert(is_assignable_to(Literal["foo"], LiteralString))
static_assert(is_assignable_to(Literal["foo"], str))
static_assert(is_assignable_to(Literal["foo"], Sequence))  # error: [missing-type-argument]
static_assert(is_assignable_to(Literal["foo"], Sequence[str]))
static_assert(is_assignable_to(Literal["foo"], Sequence[Any]))

static_assert(is_assignable_to(LiteralString, str))
static_assert(is_assignable_to(LiteralString, Sequence))  # error: [missing-type-argument]
static_assert(is_assignable_to(LiteralString, Sequence[str]))
static_assert(is_assignable_to(LiteralString, Sequence[Any]))

static_assert(not is_assignable_to(Literal["foo"], Literal["bar"]))
static_assert(not is_assignable_to(str, Literal["foo"]))
static_assert(not is_assignable_to(str, LiteralString))
```

### String literals and Sequence

String literals are assignable to `Sequence[Literal[chars...]]` because strings are sequences of
their characters.

```py
from typing import Literal, Sequence, Iterable, Collection, Reversible
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

static_assert(is_assignable_to(Literal["abba"], Sequence[Literal["a", "b"]]))
static_assert(is_assignable_to(Literal["abb"], Iterable[Literal["a", "b"]]))
static_assert(is_assignable_to(Literal["abb"], Collection[Literal["a", "b"]]))
static_assert(is_assignable_to(Literal["abb"], Reversible[Literal["a", "b"]]))
static_assert(is_assignable_to(Literal["aaa"], Sequence[Literal["a"]]))
static_assert(is_assignable_to(Literal[""], Sequence[Literal["a", "b"]]))  # empty string
static_assert(is_assignable_to(Literal["ab"], Sequence[Literal["a", "b", "c"]]))  # subset of allowed chars

# String literals are NOT assignable when they contain chars outside the allowed set
static_assert(not is_assignable_to(Literal["abc"], Sequence[Literal["a", "b"]]))  # 'c' not allowed
static_assert(not is_assignable_to(Literal["x"], Sequence[Literal["a", "b"]]))  # 'x' not allowed
static_assert(not is_assignable_to(Literal["aa"], Sequence[Literal[""]]))
```

### Byte literals

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing_extensions import Literal, LiteralString

static_assert(is_assignable_to(Literal[b"foo"], bytes))
static_assert(is_assignable_to(Literal[b"foo"], Literal[b"foo"]))

static_assert(not is_assignable_to(Literal[b"foo"], str))
static_assert(not is_assignable_to(Literal[b"foo"], LiteralString))
static_assert(not is_assignable_to(Literal[b"foo"], Literal[b"bar"]))
static_assert(not is_assignable_to(Literal[b"foo"], Literal["foo"]))
static_assert(not is_assignable_to(Literal["foo"], Literal[b"foo"]))
```

### Enum literals

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing_extensions import Literal
from enum import Enum

class Answer(Enum):
    NO = 0
    YES = 1

static_assert(is_assignable_to(Literal[Answer.YES], Literal[Answer.YES]))
static_assert(is_assignable_to(Literal[Answer.YES], Answer))
static_assert(is_assignable_to(Literal[Answer.YES, Answer.NO], Answer))
static_assert(is_assignable_to(Answer, Literal[Answer.YES, Answer.NO]))

static_assert(not is_assignable_to(Literal[Answer.YES], Literal[Answer.NO]))

class Single(Enum):
    VALUE = 1

static_assert(is_assignable_to(Literal[Single.VALUE], Single))
static_assert(is_assignable_to(Single, Literal[Single.VALUE]))
```

### Slice literals

The type of a slice literal is currently inferred as a specialization of `slice`.

```py
from ty_extensions import static_assert
from ty_extensions._internal import TypeOf, is_assignable_to

static_assert(is_assignable_to(TypeOf[1:2:3], slice))
static_assert(is_assignable_to(TypeOf[1:2:3], slice[int]))
```

## `type[…]` and class literals

In the following tests, `TypeOf[str]` is a singleton type with a single inhabitant, the class `str`.
This contrasts with `type[str]`, which represents "all possible subclasses of `str`".

Both `TypeOf[str]` and `type[str]` are subtypes of `type` and `type[object]`, which both represent
"all possible instances of `type`"; therefore both `type[str]` and `TypeOf[str]` are assignable to
`type`. `type[Any]`, on the other hand, represents a type of unknown size or inhabitants, but which
is known to be no larger than the set of possible objects represented by `type`.

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, TypeOf, is_assignable_to
from typing import Any

static_assert(is_assignable_to(type, type))
static_assert(is_assignable_to(type[object], type[object]))

static_assert(is_assignable_to(type, type[object]))
static_assert(is_assignable_to(type[object], type))

static_assert(is_assignable_to(type[str], type[object]))
static_assert(is_assignable_to(TypeOf[str], type[object]))
static_assert(is_assignable_to(type[str], type))
static_assert(is_assignable_to(TypeOf[str], type))

static_assert(is_assignable_to(type[str], type[str]))
static_assert(is_assignable_to(TypeOf[str], type[str]))

static_assert(not is_assignable_to(TypeOf[int], type[str]))
static_assert(not is_assignable_to(type, type[str]))
static_assert(not is_assignable_to(type[object], type[str]))

static_assert(is_assignable_to(type[Any], type[Any]))
static_assert(is_assignable_to(type[Any], type[object]))
static_assert(is_assignable_to(type[object], type[Any]))
static_assert(is_assignable_to(type, type[Any]))
static_assert(is_assignable_to(type[Any], type[str]))
static_assert(is_assignable_to(type[str], type[Any]))
static_assert(is_assignable_to(TypeOf[str], type[Any]))

static_assert(is_assignable_to(type[Unknown], type[Unknown]))
static_assert(is_assignable_to(type[Unknown], type[object]))
static_assert(is_assignable_to(type[object], type[Unknown]))
static_assert(is_assignable_to(type, type[Unknown]))
static_assert(is_assignable_to(type[Unknown], type[str]))
static_assert(is_assignable_to(type[str], type[Unknown]))
static_assert(is_assignable_to(TypeOf[str], type[Unknown]))

static_assert(is_assignable_to(type[Unknown], type[Any]))
static_assert(is_assignable_to(type[Any], type[Unknown]))

static_assert(not is_assignable_to(object, type[Any]))
static_assert(not is_assignable_to(str, type[Any]))

class Meta(type): ...

static_assert(is_assignable_to(type[Any], Meta))
static_assert(is_assignable_to(type[Unknown], Meta))
static_assert(is_assignable_to(Meta, type[Any]))
static_assert(is_assignable_to(Meta, type[Unknown]))

def _(x: Any):
    class AnyMeta(metaclass=x): ...
    static_assert(is_assignable_to(type[AnyMeta], type))
    static_assert(is_assignable_to(type[AnyMeta], type[object]))
    static_assert(is_assignable_to(type[AnyMeta], type[Any]))

from typing import TypeVar, Generic, Any

T_co = TypeVar("T_co", covariant=True)

class Foo(Generic[T_co]): ...
class Bar(Foo[T_co], Generic[T_co]): ...

static_assert(is_assignable_to(TypeOf[Bar[int]], type[Foo[int]]))
static_assert(is_assignable_to(TypeOf[Bar[bool]], type[Foo[int]]))
static_assert(is_assignable_to(TypeOf[Bar], type[Foo[int]]))
static_assert(is_assignable_to(TypeOf[Bar[Any]], type[Foo[int]]))
static_assert(is_assignable_to(TypeOf[Bar[Unknown]], type[Foo[int]]))
static_assert(is_assignable_to(TypeOf[Bar], type[Foo]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[Bar[Any]], type[Foo[Any]]))
static_assert(is_assignable_to(TypeOf[Bar[Any]], type[Foo[int]]))

static_assert(not is_assignable_to(TypeOf[Bar[int]], type[Foo[bool]]))
static_assert(not is_assignable_to(TypeOf[Foo[bool]], type[Bar[int]]))
```

## `type[]` is not assignable to types disjoint from `builtins.type`

```py
from typing import Any
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

static_assert(not is_assignable_to(type[Any], None))
```

## Inheriting `Any`

### Class-literal types

Class-literal types with a dynamically typed base are assignable to any type `T` where `T` is
assignable to `type`:

```py
from typing import Any
from ty_extensions import static_assert
from ty_extensions._internal import TypeOf, is_assignable_to

class A: ...

def test(x: Any, cls: type[Any], union_base: TypeOf[A] | Any):
    class Foo(x): ...
    class Bar(Any): ...
    class Baz(cls): ...
    class Mixed(Bar, x): ...
    class UnionDynamic(union_base): ...
    static_assert(is_assignable_to(TypeOf[Foo], Any))
    static_assert(is_assignable_to(TypeOf[Foo], type))
    static_assert(is_assignable_to(TypeOf[Foo], type[int]))
    static_assert(is_assignable_to(TypeOf[Foo], type[Any]))

    static_assert(is_assignable_to(TypeOf[Bar], Any))
    static_assert(is_assignable_to(TypeOf[Bar], type))
    static_assert(is_assignable_to(TypeOf[Bar], type[int]))
    static_assert(is_assignable_to(TypeOf[Bar], type[Any]))

    static_assert(is_assignable_to(TypeOf[Baz], Any))
    static_assert(is_assignable_to(TypeOf[Baz], type))
    static_assert(is_assignable_to(TypeOf[Baz], type[int]))
    static_assert(is_assignable_to(TypeOf[Baz], type[Any]))

    static_assert(is_assignable_to(TypeOf[Mixed], Any))
    static_assert(is_assignable_to(TypeOf[Mixed], type))
    static_assert(is_assignable_to(TypeOf[Mixed], type[int]))
    static_assert(is_assignable_to(TypeOf[Mixed], type[Any]))

    static_assert(is_assignable_to(TypeOf[UnionDynamic], Any))
    static_assert(is_assignable_to(TypeOf[UnionDynamic], type))
    static_assert(is_assignable_to(TypeOf[UnionDynamic], type[int]))
    static_assert(is_assignable_to(TypeOf[UnionDynamic], type[Any]))

    static_assert(not is_assignable_to(TypeOf[Foo], int))
    static_assert(not is_assignable_to(TypeOf[Bar], int))
    static_assert(not is_assignable_to(TypeOf[Baz], int))
    static_assert(not is_assignable_to(TypeOf[Mixed], int))
    static_assert(not is_assignable_to(TypeOf[UnionDynamic], int))
```

A dynamically typed base could be `int` at runtime, making the new class a subclass of `int`. The
class object is therefore assignable to `type[int]`, but not to `int`.

### Nominal instance and subclass-of types

Instances of classes that inherit directly from `Any` are assignable to arbitrary types, including
final types.

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing_extensions import Any, final

class InheritsAny(Any):
    pass

class Arbitrary:
    pass

@final
class FinalClass:
    pass

static_assert(is_assignable_to(InheritsAny, Arbitrary))
static_assert(is_assignable_to(InheritsAny, Any))
static_assert(is_assignable_to(InheritsAny, object))
static_assert(is_assignable_to(InheritsAny, FinalClass))
```

Similar for subclass-of types:

```py
static_assert(is_assignable_to(type[Any], type[Any]))
static_assert(is_assignable_to(type[object], type[Any]))
static_assert(is_assignable_to(type[Any], type[Arbitrary]))
static_assert(is_assignable_to(type[Any], type[object]))
```

## Heterogeneous tuple types

```py
from ty_extensions import static_assert, AlwaysTruthy, AlwaysFalsy
from ty_extensions._internal import is_assignable_to
from typing import Literal, Any

static_assert(is_assignable_to(tuple[()], tuple[()]))
static_assert(is_assignable_to(tuple[int], tuple[int]))
static_assert(is_assignable_to(tuple[int], tuple[Any]))
static_assert(is_assignable_to(tuple[Any], tuple[int]))
static_assert(is_assignable_to(tuple[int, str], tuple[int, str]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[int, int]))
static_assert(is_assignable_to(tuple[Any, Literal[2]], tuple[int, int]))
static_assert(is_assignable_to(tuple[Literal[1], Any], tuple[int, int]))
static_assert(is_assignable_to(tuple[()], tuple))  # error: [missing-type-argument]
static_assert(is_assignable_to(tuple[int, str], tuple))  # error: [missing-type-argument]
static_assert(is_assignable_to(tuple[Any], tuple))  # error: [missing-type-argument]

# TODO: It is not yet clear if we want the following two assertions to hold.
# See https://github.com/astral-sh/ruff/issues/15528 for more details. The
# short version is: We either need to special-case enforcement of the Liskov
# substitution principle on `__bool__` and `__len__` for tuple subclasses,
# or we need to negate these assertions.
static_assert(is_assignable_to(tuple[()], AlwaysFalsy))
static_assert(is_assignable_to(tuple[int], AlwaysTruthy))

static_assert(not is_assignable_to(tuple[()], tuple[int]))
static_assert(not is_assignable_to(tuple[int], tuple[str]))
static_assert(not is_assignable_to(tuple[int], tuple[int, str]))
static_assert(not is_assignable_to(tuple[int, str], tuple[int]))
static_assert(not is_assignable_to(tuple[int, int], tuple[Literal[1], int]))
static_assert(not is_assignable_to(tuple[Any, Literal[2]], tuple[int, str]))
```

## Assignability of heterogeneous tuple types to homogeneous tuple types

```toml
[environment]
python-version = "3.12"
```

While a homogeneous tuple type is not assignable to any heterogeneous tuple types, a heterogeneous
tuple type can be assignable to a homogeneous tuple type, and homogeneous tuple types can be
assignable to `Sequence`:

```pyi
from typing import Literal, Any, Sequence
from ty_extensions import static_assert, AlwaysFalsy
from ty_extensions._internal import is_assignable_to

static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[Literal[1, 2], ...]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[Literal[1], *tuple[Literal[2], ...]]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[*tuple[Literal[1], ...], Literal[2]]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[Literal[1], *tuple[str, ...], Literal[2]]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[Literal[1], Literal[2], *tuple[str, ...]]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[*tuple[str, ...], Literal[1], Literal[2]]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[int, ...]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[int | str, ...]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[Any, ...]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], tuple[~AlwaysFalsy, ...]))
static_assert(is_assignable_to(tuple[Literal[1], Literal[2]], Sequence[int]))
static_assert(is_assignable_to(tuple[int, ...], Sequence[int]))
static_assert(is_assignable_to(tuple[int, ...], Sequence[Any]))
static_assert(is_assignable_to(tuple[Any, ...], Sequence[int]))

static_assert(is_assignable_to(tuple[()], tuple[Literal[1, 2], ...]))
static_assert(is_assignable_to(tuple[()], tuple[int, ...]))
static_assert(is_assignable_to(tuple[()], tuple[int | str, ...]))
static_assert(is_assignable_to(tuple[()], tuple[~AlwaysFalsy, ...]))
static_assert(is_assignable_to(tuple[()], Sequence[int]))

static_assert(not is_assignable_to(tuple[int, int], tuple[str, ...]))
```

## Assignability of two mixed tuple types

```toml
[environment]
python-version = "3.12"
```

```py
from typing import Literal, Any, Sequence
from ty_extensions import static_assert, AlwaysFalsy
from ty_extensions._internal import is_assignable_to

static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[10]],
    )
)
static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...]],
    )
)

static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], *tuple[int, ...], Literal[10]],
    )
)
static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], *tuple[int, ...]],
    )
)

static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[*tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[*tuple[int, ...], Literal[10]],
    )
)
static_assert(
    is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[*tuple[int, ...]],
    )
)

static_assert(
    not is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    not is_assignable_to(
        tuple[Literal[1], Literal[2], *tuple[int, ...]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)

static_assert(
    not is_assignable_to(
        tuple[Literal[1], *tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    not is_assignable_to(
        tuple[Literal[1], *tuple[int, ...], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    not is_assignable_to(
        tuple[Literal[1], *tuple[int, ...]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)

static_assert(
    not is_assignable_to(
        tuple[*tuple[int, ...], Literal[9], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    not is_assignable_to(
        tuple[*tuple[int, ...], Literal[10]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
static_assert(
    not is_assignable_to(
        tuple[*tuple[int, ...]],
        tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[9], Literal[10]],
    )
)
```

## Assignability of the gradual tuple

```toml
[environment]
python-version = "3.12"
```

As a [special case][gradual tuple], `tuple[Any, ...]` is a [gradual][gradual form] tuple type, which
is assignable to every tuple of any length.

```py
from typing import Any
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

static_assert(is_assignable_to(tuple[Any, ...], tuple[Any, ...]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[Any]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, ...]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[int]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, int]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, *tuple[int, ...]]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[*tuple[int, ...], int]))
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, *tuple[int, ...], int]))
```

This also applies when `tuple[Any, ...]` is unpacked into a mixed tuple.

```py
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[int, *tuple[Any, ...]]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[Any, ...]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[Any]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[int, *tuple[int, ...]]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[int, ...]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[int]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...]], tuple[int, int]))

static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[*tuple[Any, ...], int]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[Any, ...]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[Any]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[*tuple[int, ...], int]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int, ...]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int]))
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int, int]))

# `*tuple[Any, ...]` can materialize to a tuple of any length as a special case,
# so this passes:
static_assert(is_assignable_to(tuple[*tuple[Any, ...], Any], tuple[*tuple[Any, ...], Any, Any]))

static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int, *tuple[Any, ...], int]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any, ...]))
static_assert(not is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int, *tuple[int, ...], int]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int, ...]))
static_assert(not is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int]))
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int, int]))
```

The same is not true of fully static tuple types, since an unbounded homogeneous tuple is defined to
be the _union_ of all tuple lengths, not the _gradual choice_ of them.

```py
static_assert(is_assignable_to(tuple[int, ...], tuple[Any, ...]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[Any]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[int, ...], tuple[int, ...]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[int]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, int]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, *tuple[int, ...]]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[*tuple[int, ...], int]))
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, *tuple[int, ...], int]))

static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int, *tuple[Any, ...]]))
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[Any, ...]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...]], tuple[Any]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...]], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int, *tuple[int, ...]]))
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int, ...]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int, int]))

static_assert(is_assignable_to(tuple[*tuple[int, ...], int], tuple[*tuple[Any, ...], int]))
static_assert(is_assignable_to(tuple[*tuple[int, ...], int], tuple[Any, ...]))
static_assert(not is_assignable_to(tuple[*tuple[int, ...], int], tuple[Any]))
static_assert(not is_assignable_to(tuple[*tuple[int, ...], int], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[*tuple[int, ...], int], tuple[*tuple[int, ...], int]))
static_assert(is_assignable_to(tuple[*tuple[int, ...], int], tuple[int, ...]))
static_assert(not is_assignable_to(tuple[*tuple[int, ...], int], tuple[int]))
static_assert(not is_assignable_to(tuple[*tuple[int, ...], int], tuple[int, int]))

static_assert(is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[int, *tuple[Any, ...], int]))
static_assert(is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[Any, ...]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[Any]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[Any, Any]))
static_assert(is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[int, *tuple[int, ...], int]))
static_assert(is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[int, ...]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[int]))
static_assert(not is_assignable_to(tuple[int, *tuple[int, ...], int], tuple[int, int]))
```

## Union types

```py
from ty_extensions import AlwaysTruthy, AlwaysFalsy, static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing_extensions import Literal, Any, LiteralString

static_assert(is_assignable_to(int, int | str))
static_assert(is_assignable_to(str, int | str))
static_assert(is_assignable_to(int | str, int | str))
static_assert(is_assignable_to(str | int, int | str))
static_assert(is_assignable_to(Literal[1], int | str))
static_assert(is_assignable_to(Literal[1], Unknown | str))
static_assert(is_assignable_to(Literal[1] | Literal[2], Literal[1] | Literal[2]))
static_assert(is_assignable_to(Literal[1] | Literal[2], int))
static_assert(is_assignable_to(Literal[1] | None, int | None))
static_assert(is_assignable_to(Any, int | str))
static_assert(is_assignable_to(Any | int, int))
static_assert(is_assignable_to(str, int | Any))

static_assert(not is_assignable_to(int | None, int))
static_assert(not is_assignable_to(int | None, str | None))
static_assert(not is_assignable_to(Literal[1] | None, int))
static_assert(not is_assignable_to(Literal[1] | None, str | None))
static_assert(not is_assignable_to(Any | int | str, int))

# TODO: No errors
# error: [static-assert-error]
static_assert(is_assignable_to(bool, Literal[False] | AlwaysTruthy))
# error: [static-assert-error]
static_assert(is_assignable_to(bool, Literal[True] | AlwaysFalsy))
# error: [static-assert-error]
static_assert(is_assignable_to(LiteralString, Literal[""] | AlwaysTruthy))
static_assert(not is_assignable_to(Literal[True] | AlwaysFalsy, Literal[False] | AlwaysTruthy))
```

## Intersection types

```pyi
from ty_extensions import static_assert, AlwaysTruthy, AlwaysFalsy
from ty_extensions._internal import is_assignable_to
from typing_extensions import Any, Literal, final, LiteralString

class Parent: ...
class Child1(Parent): ...
class Child2(Parent): ...
class Grandchild(Child1, Child2): ...
class Unrelated: ...

static_assert(is_assignable_to(Child1 & Child2, Child1))
static_assert(is_assignable_to(Child1 & Child2, Child2))
static_assert(is_assignable_to(Child1 & Child2, Parent))
static_assert(is_assignable_to(Child1 & Parent, Parent))

static_assert(is_assignable_to(Parent & Unrelated, Parent))
static_assert(is_assignable_to(Child1 & Unrelated, Child1))
static_assert(is_assignable_to(Child1 & Unrelated & Child2, Child1 & Unrelated))

static_assert(is_assignable_to(Child1 & ~Child2, Child1))
static_assert(is_assignable_to(Child1 & ~Child2, Parent))
static_assert(is_assignable_to(Child1 & ~Grandchild, Parent))

static_assert(is_assignable_to(Child1 & Child2, Child1 & Child2))
static_assert(is_assignable_to(Child1 & Child2, Child2 & Child1))
static_assert(is_assignable_to(Grandchild, Child1 & Child2))
static_assert(not is_assignable_to(Child1 & Child2, Parent & Unrelated))

static_assert(not is_assignable_to(Parent, Parent & Unrelated))
static_assert(not is_assignable_to(int, int & ~Literal[1]))
# The literal `1` is not assignable to `Parent`, so the intersection of int and Parent is definitely an int that is not `1`
static_assert(is_assignable_to(int & Parent, int & ~Literal[1]))
static_assert(not is_assignable_to(int, ~int))
static_assert(not is_assignable_to(int, ~Literal[1]))

static_assert(is_assignable_to(~Parent, ~Child1))
static_assert(not is_assignable_to(~Parent, Parent))
static_assert(not is_assignable_to(Unrelated & ~Parent, Parent))

# Intersection with `Any` dominates the left hand side of intersections
static_assert(is_assignable_to(Any & Parent, Parent))
static_assert(is_assignable_to(Any & Child1, Parent))
static_assert(is_assignable_to(Any & Child2 & ~Child1, Parent))
static_assert(is_assignable_to(Any & Parent, Unrelated))
static_assert(is_assignable_to(Any & Parent, Parent & Unrelated))
static_assert(is_assignable_to(Any & Parent & Unrelated, Parent))
static_assert(is_assignable_to(Any & Parent & Unrelated, Parent & Unrelated))

# Even Any & ~Parent is assignable to Parent, since it could be Never
static_assert(is_assignable_to(Any & ~Parent, Parent))
static_assert(is_assignable_to(Any & ~Parent, ~Parent))

# Intersection with `Any` is effectively ignored on the right hand side for the sake of assignment
static_assert(is_assignable_to(Parent, Any & Parent))
static_assert(is_assignable_to(Parent, Parent | Any & Unrelated))
static_assert(is_assignable_to(Child1, Any & Parent))
static_assert(not is_assignable_to(Literal[1], Any & Parent))
static_assert(not is_assignable_to(Unrelated, Any & Parent))

# Intersections with Any on both sides combine the above logic - the LHS dominates and Any is ignored on the right hand side
static_assert(is_assignable_to(Any & Parent, Any & Parent))
static_assert(is_assignable_to(Any & Unrelated, Any & Parent))
static_assert(is_assignable_to(Any & Parent & Unrelated, Any & Parent & Unrelated))
static_assert(is_assignable_to(Unrelated & Any, Unrelated & ~Any))
static_assert(is_assignable_to(Literal[1] & Any, Unrelated & ~Any))

# TODO: No errors
# The condition `is_assignable_to(T & U, U)` should still be satisfied after the following transformations:
# `LiteralString & AlwaysTruthy` -> `LiteralString & ~Literal[""]`
# error: [static-assert-error]
static_assert(is_assignable_to(LiteralString & ~Literal[""], AlwaysTruthy))
# error: [static-assert-error]
static_assert(is_assignable_to(LiteralString & ~Literal["", "a"], AlwaysTruthy))
# `LiteralString & ~AlwaysFalsy`  -> `LiteralString & ~Literal[""]`
# error: [static-assert-error]
static_assert(is_assignable_to(LiteralString & ~Literal[""], ~AlwaysFalsy))
# error: [static-assert-error]
static_assert(is_assignable_to(LiteralString & ~Literal["", "a"], ~AlwaysFalsy))
```

## Callable types with Unknown/missing return type

See <https://github.com/astral-sh/ty/issues/2363>, a property test failure involving
`~type & ~((...) -> Unknown)` not being assignable to `~type`. Since `~type & ~Callable` is a subset
of `~type`, the intersection should be assignable to `~type`.

The root cause was that we failed to properly materialize a `Callable[..., Unknown]` type when the
`Unknown` return type originated from a missing annotation.

```pyi
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, RegularCallableTypeOf, is_assignable_to
from typing import Callable

# `Callable[..., Unknown]` has explicit Unknown return type
static_assert(is_assignable_to(~type & ~Callable[..., Unknown], ~type))

# Function with no return annotation (has implicit Unknown return type internally)
def no_return_annotation(*args, **kwargs): ...

# `RegularCallableTypeOf[no_return_annotation]` has `returns: None` internally (no annotation)
static_assert(is_assignable_to(~type & ~RegularCallableTypeOf[no_return_annotation], ~type))
```

## Intersections with non-fully-static negated elements

A type can be _assignable_ to an intersection containing negated elements only if the _bottom_
materialization of that type is disjoint from the _bottom_ materialization of all negated elements
in the intersection. This differs from subtyping, which should do the disjointness check against the
_top_ materialization of the negated elements.

```pyi
from typing_extensions import Any, Never, Sequence
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

# The bottom materialization of `tuple[Any]` is `tuple[Never]`,
# which simplifies to `Never`, so `tuple[int]` and `tuple[()]` are
# both assignable to `~tuple[Any]`
static_assert(is_assignable_to(tuple[int], ~tuple[Any]))
static_assert(is_assignable_to(tuple[()], ~tuple[Any]))

# But the bottom materialization of `tuple[Any, ...]` is `tuple[Never, ...]`,
# which simplifies to `tuple[()]`, so `tuple[int]` is still assignable to
# `~tuple[Any, ...]`, but `tuple[()]` is not
static_assert(is_assignable_to(tuple[int], ~tuple[Any, ...]))
static_assert(not is_assignable_to(tuple[()], ~tuple[Any, ...]))

# Similarly, the bottom materialization of `Sequence[Any]` is `Sequence[Never]`,
# so `tuple[()]` is not assignable to `~Sequence[Any]`, and nor is `list[Never]`,
# since both `tuple[()]` and `list[Never]` are subtypes of `Sequence[Never]`.
# `tuple[int, ...]` is also not assignable to `~Sequence[Any]`, as although it is
# not a subtype of `Sequence[Never]` it is also not disjoint from `Sequence[Never]`:
# `tuple[()]` is a subtype of both `Sequence[Never]` and `tuple[int, ...]`, so
# `tuple[int, ...]` and `Sequence[Never]` cannot be considered disjoint.
#
# Other `list` and `tuple` specializations *are* assignable to `~Sequence[Any]`,
# however, since there are many fully static materializations of `Sequence[Any]`
# that would be disjoint from a given `list` or `tuple` specialization.
static_assert(not is_assignable_to(tuple[()], ~Sequence[Any]))
static_assert(not is_assignable_to(list[Never], ~Sequence[Any]))
static_assert(not is_assignable_to(tuple[int, ...], ~Sequence[Any]))

# TODO: should pass (`tuple[int]` should be considered disjoint from `Sequence[Never]`)
static_assert(is_assignable_to(tuple[int], ~Sequence[Any]))  # error: [static-assert-error]

# TODO: should pass (`list[int]` should be considered disjoint from `Sequence[Never]`)
static_assert(is_assignable_to(list[int], ~Sequence[Any]))  # error: [static-assert-error]

# If the left-hand side is also not fully static,
# the left-hand side will be assignable to the right if the bottom materialization
# of the left-hand side is disjoint from the bottom materialization of all negated
# elements on the right-hand side

# `tuple[Any, ...]` cannot be assignable to `~tuple[Any, ...]`,
# because the bottom materialization of `tuple[Any, ...]` is
# `tuple[()]`, and `tuple[()]` is not disjoint from itself
static_assert(not is_assignable_to(tuple[Any, ...], ~tuple[Any, ...]))

# but `tuple[Any]` is assignable to `~tuple[Any]`,
# as the bottom materialization of `tuple[Any]` is `Never`,
# and `Never` *is* disjoint from itself
static_assert(is_assignable_to(tuple[Any], ~tuple[Any]))

# The same principle applies for non-fully-static `list` specializations.
# TODO: this should pass (`Bottom[list[Any]]` should simplify to `Never`)
static_assert(is_assignable_to(list[Any], ~list[Any]))  # error: [static-assert-error]

# `Bottom[list[Any]]` is `Never`, which is disjoint from `Bottom[Sequence[Any]]`
# (which is `Sequence[Never]`).
# TODO: this should pass (`Bottom[list[Any]]` should simplify to `Never`)
static_assert(is_assignable_to(list[Any], ~Sequence[Any]))  # error: [static-assert-error]
```

## General properties

See also: our property tests in `property_tests.rs`.

### Everything is assignable to `object`

`object` is Python's top type; the set of all possible objects at runtime:

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing import Literal, Any

static_assert(is_assignable_to(str, object))
static_assert(is_assignable_to(Literal[1], object))
static_assert(is_assignable_to(object, object))
static_assert(is_assignable_to(type, object))
static_assert(is_assignable_to(Any, object))
static_assert(is_assignable_to(Unknown, object))
static_assert(is_assignable_to(type[object], object))
static_assert(is_assignable_to(type[str], object))
static_assert(is_assignable_to(type[Any], object))
```

### Every type is assignable to `Any` / `Unknown`

`Any` and `Unknown` are gradual types. They could materialize to any given type at runtime, and so
any type is assignable to them:

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing import Literal, Any

static_assert(is_assignable_to(str, Any))
static_assert(is_assignable_to(Literal[1], Any))
static_assert(is_assignable_to(object, Any))
static_assert(is_assignable_to(type, Any))
static_assert(is_assignable_to(Any, Any))
static_assert(is_assignable_to(Unknown, Any))
static_assert(is_assignable_to(type[object], Any))
static_assert(is_assignable_to(type[str], Any))
static_assert(is_assignable_to(type[Any], Any))

static_assert(is_assignable_to(str, Unknown))
static_assert(is_assignable_to(Literal[1], Unknown))
static_assert(is_assignable_to(object, Unknown))
static_assert(is_assignable_to(type, Unknown))
static_assert(is_assignable_to(Any, Unknown))
static_assert(is_assignable_to(Unknown, Unknown))
static_assert(is_assignable_to(type[object], Unknown))
static_assert(is_assignable_to(type[str], Unknown))
static_assert(is_assignable_to(type[Any], Unknown))
```

### `Never` is assignable to every type

`Never` is Python's bottom type: the empty set, a type with no inhabitants. It is therefore
assignable to any arbitrary type.

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing_extensions import Never, Any, Literal

static_assert(is_assignable_to(Never, str))
static_assert(is_assignable_to(Never, Literal[1]))
static_assert(is_assignable_to(Never, object))
static_assert(is_assignable_to(Never, type))
static_assert(is_assignable_to(Never, Any))
static_assert(is_assignable_to(Never, Unknown))
static_assert(is_assignable_to(Never, type[object]))
static_assert(is_assignable_to(Never, type[str]))
static_assert(is_assignable_to(Never, type[Any]))
```

### `Any` / `Unknown` is assignable to `Never`

`Any` and `Unknown` are gradual types. They could materialize to any given type at runtime,
including `Never`.

```pyi
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing_extensions import Never, Any

static_assert(is_assignable_to(Any, Never))
static_assert(is_assignable_to(Unknown, Never))
static_assert(is_assignable_to(Any | Unknown, Never))
static_assert(is_assignable_to(Any & int, Never))
static_assert(is_assignable_to(Unknown & int, Never))
static_assert(not is_assignable_to(Any | int, Never))
static_assert(not is_assignable_to(Unknown | int, Never))
```

## Callable

The examples provided below are only a subset of the possible cases and include the ones with
gradual types. The cases with fully static types and using different combinations of parameter kinds
are covered in the [subtyping tests](./is_subtype_of.md#callable).

### Return type

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, RegularCallableTypeOf, is_assignable_to
from typing import Any, Callable

static_assert(is_assignable_to(Callable[[], Any], Callable[[], int]))
static_assert(is_assignable_to(Callable[[], int], Callable[[], Any]))

static_assert(is_assignable_to(Callable[[], int], Callable[[], float]))
static_assert(not is_assignable_to(Callable[[], float], Callable[[], int]))
```

The return types should be checked even if the parameter types uses gradual form (`...`).

```py
static_assert(is_assignable_to(Callable[..., int], Callable[..., float]))
static_assert(not is_assignable_to(Callable[..., float], Callable[..., int]))
```

And, if there is no return type, the return type is `Unknown`.

```py
static_assert(is_assignable_to(Callable[[], Unknown], Callable[[], int]))
static_assert(is_assignable_to(Callable[[], int], Callable[[], Unknown]))
```

### Parameter types

A `Callable` which uses the gradual form (`...`) for the parameter types is consistent with any
input signature.

```py
from ty_extensions import static_assert
from ty_extensions._internal import RegularCallableTypeOf, is_assignable_to
from typing import Any, Callable

static_assert(is_assignable_to(Callable[[], None], Callable[..., None]))
static_assert(is_assignable_to(Callable[..., None], Callable[..., None]))
static_assert(is_assignable_to(Callable[[int, float, str], None], Callable[..., None]))
```

Even if it includes any other parameter kinds.

```py
def positional_only(a: int, b: int, /) -> None: ...
def positional_or_keyword(a: int, b: int) -> None: ...
def variadic(*args: int) -> None: ...
def keyword_only(*, a: int, b: int) -> None: ...
def keyword_variadic(**kwargs: int) -> None: ...
def mixed(a: int, /, b: int, *args: int, c: int, **kwargs: int) -> None: ...

static_assert(is_assignable_to(RegularCallableTypeOf[positional_only], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[positional_or_keyword], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[variadic], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[keyword_only], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[keyword_variadic], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[mixed], Callable[..., None]))
```

And, even if the parameters are unannotated.

```py
def positional_only(a, b, /) -> None: ...
def positional_or_keyword(a, b) -> None: ...
def variadic(*args) -> None: ...
def keyword_only(*, a, b) -> None: ...
def keyword_variadic(**kwargs) -> None: ...
def mixed(a, /, b, *args, c, **kwargs) -> None: ...

static_assert(is_assignable_to(RegularCallableTypeOf[positional_only], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[positional_or_keyword], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[variadic], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[keyword_only], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[keyword_variadic], Callable[..., None]))
static_assert(is_assignable_to(RegularCallableTypeOf[mixed], Callable[..., None]))
```

### Unpacked positional parameters with a required suffix

A variadic positional parameter can accept both the unpacked tuple and a required positional
parameter following that tuple.

```py
from typing import Any, Callable, Never, Unpack, cast
from ty_extensions import static_assert
from ty_extensions._internal import RegularCallableTypeOf, is_assignable_to

def expects_suffix(callback: Callable[[Unpack[tuple[str, ...]], None], None]) -> None: ...
def accepts_unknown(*args): ...

expects_suffix(accepts_unknown)
```

The variadic parameter's annotation must be compatible with the unpacked elements and the required
suffix.

```py
def accepts_objects(*args: object) -> None: ...
def accepts_strings_or_none(*args: str | None) -> None: ...
def accepts_strings(*args: str) -> None: ...

expects_suffix(accepts_objects)
expects_suffix(accepts_strings_or_none)
expects_suffix(accepts_strings)  # error: [invalid-argument-type]

static_assert(
    is_assignable_to(
        RegularCallableTypeOf[accepts_objects],
        Callable[[Unpack[tuple[str, ...]], None], None],
    )
)
static_assert(
    is_assignable_to(
        RegularCallableTypeOf[accepts_strings_or_none],
        Callable[[Unpack[tuple[str, ...]], None], None],
    )
)
static_assert(
    not is_assignable_to(
        RegularCallableTypeOf[accepts_strings],
        Callable[[Unpack[tuple[str, ...]], None], None],
    )
)
```

A required keyword-only parameter cannot be supplied by the positional callback signature.

```py
def requires_keyword(*args: object, value: int) -> None: ...

expects_suffix(requires_keyword)  # error: [invalid-argument-type]
```

A required positional prefix does not prevent the source variadic parameter from also accepting the
target's required suffix.

```py
def expects_prefix_and_suffix(
    callback: Callable[[int, Unpack[tuple[str, ...]], None], None],
) -> None: ...
def accepts_prefixed_objects(first: int, *args: object) -> None: ...

expects_prefix_and_suffix(accepts_prefixed_objects)
```

A required suffix can align with a longer suffix or an equivalent positional prefix when all the
unpacked elements have the same type.

```py
def requires_one_integer(*args: *tuple[*tuple[int, ...], int]) -> None: ...

longer_suffix: Callable[[*tuple[int, ...], int, int], None] = requires_one_integer
equivalent_prefix: Callable[[int, *tuple[int, ...]], None] = requires_one_integer

type OneOrMoreIntegers = RegularCallableTypeOf[requires_one_integer]

static_assert(is_assignable_to(OneOrMoreIntegers, Callable[[*tuple[int, ...], int, int], None]))
static_assert(is_assignable_to(OneOrMoreIntegers, Callable[[int, *tuple[int, ...]], None]))
```

A type alias for the variadic element does not prevent the required suffix from matching.

```py
type Integer = int

def requires_one_aliased_integer(*args: *tuple[*tuple[Integer, ...], int]) -> None: ...

type AliasedIntegers = RegularCallableTypeOf[requires_one_aliased_integer]

static_assert(is_assignable_to(AliasedIntegers, Callable[[int, *tuple[int, ...]], None]))
```

A longer suffix is aligned from the end when its other elements fit the source variadic parameter.

```py
def requires_string_suffix(*args: *tuple[*tuple[object, ...], str]) -> None: ...
def requires_string_after_integers(*args: *tuple[*tuple[int, ...], str]) -> None: ...

type StringSuffix = RegularCallableTypeOf[requires_string_suffix]
type IntegerStringSuffix = RegularCallableTypeOf[requires_string_after_integers]

static_assert(is_assignable_to(StringSuffix, Callable[[*tuple[object, ...], int, str], None]))
static_assert(is_assignable_to(IntegerStringSuffix, Callable[[*tuple[int, ...], int, str], None]))
```

Gradual variadic elements remain assignable in both directions.

```py
type GradualSuffix = Callable[[*tuple[Any, ...], int], None]

static_assert(is_assignable_to(OneOrMoreIntegers, GradualSuffix))
static_assert(is_assignable_to(GradualSuffix, OneOrMoreIntegers))
```

A positional parameter cannot also be filled by a target keyword argument.

```py
def occupies_keyword(a: int, *args: int, **kwargs: int) -> None: ...
def accepts_keyword(*args: *tuple[*tuple[int, ...], int], **kwargs: int) -> None: ...

type OccupiesKeyword = RegularCallableTypeOf[occupies_keyword]
type AcceptsKeyword = RegularCallableTypeOf[accepts_keyword]

static_assert(not is_assignable_to(OccupiesKeyword, AcceptsKeyword))
```

An uninhabited keyword parameter cannot collide with an occupied positional parameter.

```py
type Bottom = Never

def rejects_keywords(*args: *tuple[*tuple[int, ...], int], **kwargs: Bottom) -> None: ...
def rejects_named_keyword(*args: *tuple[*tuple[int, ...], int], a: Never = cast(Never, 0)) -> None: ...

static_assert(is_assignable_to(OccupiesKeyword, RegularCallableTypeOf[rejects_keywords]))
static_assert(is_assignable_to(OccupiesKeyword, RegularCallableTypeOf[rejects_named_keyword]))
```

A suffix cannot be extended with elements that the source variadic parameter rejects.

```py
# error: [invalid-assignment]
incompatible_suffix: Callable[[*tuple[int, ...], str, str], None] = requires_string_after_integers
```

### Fixed-length unpacked positional parameters

An unpacked fixed-length tuple accepts exactly its declared positional arguments, including when the
tuple is empty. Equivalent unpacked source and target tuples are compatible.

```py
from typing import Callable, Unpack
from ty_extensions import static_assert
from ty_extensions._internal import RegularCallableTypeOf, is_assignable_to

def accepts_no_arguments(*args: Unpack[tuple[()]]) -> None: ...
def accepts_one_integer(*args: Unpack[tuple[int]]) -> None: ...
def accepts_strings(*args: str) -> None: ...

empty_callback: Callable[[Unpack[tuple[()]]], None] = accepts_no_arguments
fixed_callback: Callable[[Unpack[tuple[int]]], None] = accepts_one_integer
fixed_strings: Callable[[Unpack[tuple[str, str]]], None] = accepts_strings
empty_strings: Callable[[Unpack[tuple[()]]], None] = accepts_strings

static_assert(is_assignable_to(RegularCallableTypeOf[accepts_no_arguments], Callable[[Unpack[tuple[()]]], None]))
static_assert(is_assignable_to(RegularCallableTypeOf[accepts_one_integer], Callable[[Unpack[tuple[int]]], None]))
```

Empty and exhausted fixed-length source tuples cannot satisfy a target with additional positional
arguments or an open-ended variadic parameter.

```py
# error: [invalid-assignment]
empty_with_prefix: Callable[[int, Unpack[tuple[str, ...]], None], None] = accepts_no_arguments

# error: [invalid-assignment]
empty_with_suffix: Callable[[Unpack[tuple[str, ...]], None], None] = accepts_no_arguments

# error: [invalid-assignment]
exhausted_with_suffix: Callable[[int, Unpack[tuple[str, ...]], None], None] = accepts_one_integer

# error: [invalid-assignment]
callback: Callable[[Unpack[tuple[tuple[int], ...]], tuple[int]], None] = accepts_one_integer

static_assert(
    not is_assignable_to(
        RegularCallableTypeOf[accepts_one_integer],
        Callable[[Unpack[tuple[tuple[int], ...]], tuple[int]], None],
    )
)
```

### Function types

```py
from typing import Any, Callable

def f(x: Any) -> str:
    return ""

def g(x: Any) -> int:
    return 1

c: Callable[[Any], str] = f

# error: [invalid-assignment] "Object of type `def g(x: Any) -> int` is not assignable to `(Any, /) -> str`"
c: Callable[[Any], str] = g
```

A function with no explicit return type should be assignable to a callable with a return type of
`Any`.

```py
def h():
    return

c: Callable[[], Any] = h
```

And, similarly for parameters with no annotations:

```py
def i(a, b, /) -> None:
    return

c: Callable[[Any, Any], None] = i
```

Additionally, a function definition that includes both `*args` and `**kwargs` parameters that are
annotated as `Any` or kept unannotated should be assignable to a callable with `...` as the
parameter type.

```py
def variadic_without_annotation(*args, **kwargs):
    return

def variadic_with_annotation(*args: Any, **kwargs: Any) -> Any:
    return

c: Callable[..., Any] = variadic_without_annotation
c: Callable[..., Any] = variadic_with_annotation
```

### Method types

```py
from typing import Any, Callable

class A:
    def f(self, x: Any) -> str:
        return ""

    def g(self, x: Any) -> int:
        return 1

c: Callable[[Any], str] = A().f

# error: [invalid-assignment] "Object of type `bound method A.g(x: Any) -> int` is not assignable to `(Any, /) -> str`"
c: Callable[[Any], str] = A().g
```

### Generic method types with gradual class return types

A generic receiver makes signature comparison lazy without changing whether gradual class types are
assignable.

```toml
[environment]
python-version = "3.12"
```

```py
from typing import Any, Callable
from ty_extensions._internal import Unknown

class C:
    def concrete[T](self: T) -> type[int]:
        return int

    def gradual[T](self: T) -> type[Any]:
        return int

accepts_any: Callable[[], type[Any]] = C().concrete
accepts_unknown: Callable[[], type[Unknown]] = C().concrete
accepts_concrete: Callable[[], type[int]] = C().gradual
```

### Class literal types

```py
from typing import Any, Callable
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

c: Callable[[object], type] = type
c: Callable[[str], Any] = str
c: Callable[[str], Any] = int

# error: [invalid-assignment]
c: Callable[[str], Any] = object

class A:
    def __init__(self, x: int) -> None: ...

a: Callable[[int], A] = A

class C:
    def __new__(cls, *args, **kwargs) -> "C":
        return super().__new__(cls)

    def __init__(self, x: int) -> None: ...

c: Callable[[int], C] = C

def f(a: Callable[..., Any], b: Callable[[Any], Any]): ...

f(tuple, tuple)

def g(a: Callable[[Any, Any], Any]): ...

# error: [invalid-argument-type] "Argument to function `g` is incorrect: Expected `(Any, Any, /) -> Any`, found `<class 'tuple'>`"
g(tuple)
```

### Generic class literal types

```toml
[environment]
python-version = "3.12"
```

```py
from typing import Callable

class B[T]:
    def __init__(self, x: T) -> None: ...

b: Callable[[int], B[int]] = B[int]

class C[T]:
    def __new__(cls, *args, **kwargs) -> "C[T]":
        return super().__new__(cls)

    def __init__(self, x: T) -> None: ...

c: Callable[[int], C[int]] = C[int]
```

### Overloads

`overloaded.pyi`:

```pyi
from typing import Any, overload

@overload
def overloaded() -> None: ...
@overload
def overloaded(a: str) -> str: ...
@overload
def overloaded(a: str, b: Any) -> str: ...
```

```py
from overloaded import overloaded
from typing import Any, Callable

c: Callable[[], None] = overloaded
c: Callable[[str], str] = overloaded
c: Callable[[str, Any], Any] = overloaded
c: Callable[..., str] = overloaded

# error: [invalid-assignment]
c: Callable[..., int] = overloaded

# error: [invalid-assignment]
c: Callable[[int], str] = overloaded
```

### Classes with `__call__`

```py
from typing import Callable, Any
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

class TakesAny:
    def __call__(self, a: Any) -> str:
        return ""

class ReturnsAny:
    def __call__(self, a: str) -> Any: ...

static_assert(is_assignable_to(TakesAny, Callable[[int], str]))
static_assert(not is_assignable_to(TakesAny, Callable[[int], int]))

static_assert(is_assignable_to(ReturnsAny, Callable[[str], int]))
static_assert(not is_assignable_to(ReturnsAny, Callable[[int], int]))

from functools import partial

def f(x: int, y: str) -> None: ...

c1: Callable[[int], None] = partial(f, y="a")
```

### Generic classes with `__call__`

```toml
[environment]
python-version = "3.12"
```

```py
from typing_extensions import Callable, Any, Generic, TypeVar, ParamSpec
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

T = TypeVar("T")
P = ParamSpec("P")

class Foo[T]:
    def __call__(self): ...

class FooLegacy(Generic[T]):
    def __call__(self): ...

class Bar[T, **P]:
    def __call__(self): ...

class BarLegacy(Generic[T, P]):
    def __call__(self): ...

static_assert(is_assignable_to(Foo, Callable[..., Any]))  # error: [missing-type-argument]
static_assert(is_assignable_to(FooLegacy, Callable[..., Any]))  # error: [missing-type-argument]
static_assert(is_assignable_to(Bar, Callable[..., Any]))  # error: [missing-type-argument]
static_assert(is_assignable_to(BarLegacy, Callable[..., Any]))  # error: [missing-type-argument]

class Spam[T]: ...
class SpamLegacy(Generic[T]): ...
class Eggs[T, **P]: ...
class EggsLegacy(Generic[T, P]): ...

static_assert(not is_assignable_to(Spam, Callable[..., Any]))  # error: [missing-type-argument]
static_assert(not is_assignable_to(SpamLegacy, Callable[..., Any]))  # error: [missing-type-argument]
static_assert(not is_assignable_to(Eggs, Callable[..., Any]))  # error: [missing-type-argument]
static_assert(not is_assignable_to(EggsLegacy, Callable[..., Any]))  # error: [missing-type-argument]
```

### Classes with `__call__` as attribute

An instance type is assignable to a compatible callable type if the instance type's class has a
callable `__call__` attribute.

```py
from __future__ import annotations

from typing import Callable
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

def call_impl(a: A, x: int) -> str:
    return ""

class A:
    __call__: Callable[[A, int], str] = call_impl

static_assert(is_assignable_to(A, Callable[[int], str]))
static_assert(not is_assignable_to(A, Callable[[int], int]))
reveal_type(A()(1))  # revealed: str
```

### Subclass of

#### Type of a class with constructor methods

```py
from typing import Callable
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

class A:
    def __init__(self, x: int) -> None: ...

class B:
    def __new__(cls, x: str) -> "B":
        return super().__new__(cls)

static_assert(is_assignable_to(type[A], Callable[[int], A]))
static_assert(not is_assignable_to(type[A], Callable[[str], A]))

static_assert(is_assignable_to(type[B], Callable[[str], B]))
static_assert(not is_assignable_to(type[B], Callable[[int], B]))
```

#### Type with no generic parameters

```py
from typing import Callable, Any
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

static_assert(is_assignable_to(type, Callable[..., Any]))
```

### Generic callables

A generic callable can be considered equivalent to an intersection of all of its possible
specializations. That means that a generic callable is assignable to any particular specialization.
(If someone expects a function that works with a particular specialization, it's fine to hand them
the generic callable.)

```py
from typing import Callable, Self
from ty_extensions import static_assert
from ty_extensions._internal import (
    ConstraintSet,
    RegularCallableTypeOf,
    TypeOf,
    is_assignable_to,
    is_constraint_set_assignable_to,
)

def identity[T](t: T) -> T:
    return t

static_assert(is_assignable_to(TypeOf[identity], Callable[[int], int]))
static_assert(is_assignable_to(TypeOf[identity], Callable[[str], str]))
# TODO: This should not be assignable. A generic callable must use one coherent specialization.
# error: [static-assert-error]
static_assert(not is_assignable_to(TypeOf[identity], Callable[[str], int]))

static_assert(is_assignable_to(RegularCallableTypeOf[identity], Callable[[int], int]))
static_assert(is_assignable_to(RegularCallableTypeOf[identity], Callable[[str], str]))
# error: [static-assert-error]
static_assert(not is_assignable_to(RegularCallableTypeOf[identity], Callable[[str], int]))

def bounded[T_bound: object](t: T_bound) -> T_bound:
    return t

static_assert(is_assignable_to(TypeOf[bounded], Callable[[str], str]))
# error: [static-assert-error]
static_assert(not is_assignable_to(TypeOf[bounded], Callable[[str], int]))

static_assert(is_assignable_to(RegularCallableTypeOf[bounded], Callable[[str], str]))
# error: [static-assert-error]
static_assert(not is_assignable_to(RegularCallableTypeOf[bounded], Callable[[str], int]))

def constrained[T_constrained: (str, bytes)](t: T_constrained) -> T_constrained:
    return t

static_assert(is_assignable_to(TypeOf[constrained], Callable[[str], str]))
static_assert(is_assignable_to(TypeOf[constrained], Callable[[bytes], bytes]))
# error: [static-assert-error]
static_assert(not is_assignable_to(TypeOf[constrained], Callable[[str], int]))

static_assert(is_assignable_to(RegularCallableTypeOf[constrained], Callable[[str], str]))
static_assert(is_assignable_to(RegularCallableTypeOf[constrained], Callable[[bytes], bytes]))
# error: [static-assert-error]
static_assert(not is_assignable_to(RegularCallableTypeOf[constrained], Callable[[str], int]))

# This exercises the case where a method's inferable set includes an outer class typevar in
# addition to the typevars directly bound by the method's own generic context.
class MethodCarrier[A_method]:
    def method[T_method: str](self: "MethodCarrier[A_method]", t: T_method) -> tuple[A_method, T_method]:
        raise NotImplementedError

static_assert(
    is_assignable_to(
        TypeOf[MethodCarrier.method],
        Callable[[MethodCarrier[int], str], tuple[int, str]],
    )
)
static_assert(
    is_assignable_to(
        RegularCallableTypeOf[MethodCarrier.method],
        Callable[[MethodCarrier[int], str], tuple[int, str]],
    )
)
static_assert(
    not is_assignable_to(
        TypeOf[MethodCarrier.method],
        Callable[[MethodCarrier[int], int], tuple[int, int]],
    )
)
static_assert(
    not is_assignable_to(
        RegularCallableTypeOf[MethodCarrier.method],
        Callable[[MethodCarrier[int], int], tuple[int, int]],
    )
)

class SelfCarrier[A_self]:
    def method[T_self: str](self: Self, t: T_self) -> tuple[A_self, T_self]:
        raise NotImplementedError

# TODO: This should be assignable. The unbound method type currently loses the outer class type
# argument carried through `Self`, so the return type degrades to `tuple[Unknown, T_self]` before
# the generic-callable assignability logic runs.
static_assert(
    is_assignable_to(
        TypeOf[SelfCarrier.method],
        Callable[[SelfCarrier[int], str], tuple[int, str]],
    )
)
static_assert(
    is_assignable_to(
        RegularCallableTypeOf[SelfCarrier.method],
        Callable[[SelfCarrier[int], str], tuple[int, str]],
    )
)
```

A constraint-producing comparison must keep an enclosing class variable symbolic while solving the
surrounding callable's return variable:

```py
class OuterCarrier[A_outer]:
    def method(self) -> A_outer:
        raise NotImplementedError

    def check[R](self) -> None:
        actual = is_constraint_set_assignable_to(RegularCallableTypeOf[OuterCarrier[A_outer].method], Callable[..., R])
        expected = ConstraintSet.lower_bound(A_outer, R)
        static_assert(actual == expected)
```

The reverse is not true — if someone expects a generic function that can be called with any
specialization, we cannot hand them a function that only works with one specialization.

```py
static_assert(not is_assignable_to(Callable[[int], int], TypeOf[identity]))
static_assert(not is_assignable_to(Callable[[str], str], TypeOf[identity]))
static_assert(not is_assignable_to(Callable[[str], int], TypeOf[identity]))

static_assert(not is_assignable_to(Callable[[int], int], RegularCallableTypeOf[identity]))
static_assert(not is_assignable_to(Callable[[str], str], RegularCallableTypeOf[identity]))
static_assert(not is_assignable_to(Callable[[str], int], RegularCallableTypeOf[identity]))
```

## Generics

### Assignability of generic types parameterized by gradual types

If `Foo` is a class that is generic over a single type variable `T`, `Foo[X]` will be assignable to
`Foo[Y]` iff `X` is assignable to `Y` AND `Y` is assignable to `X`.

This might appear to be the same principle as the "gradual equivalence" relation, but it is subtly
different. Two gradual types can be said to be "gradually equivalent" iff they have exactly the same
sets of possible materializations -- if they represent the same sets of possible types (the same
sets of sets of possible runtime objects). By this principle `int | Any` is gradually equivalent to
`Unknown | int`, since they have exactly the same sets of possible materializations. But
`bool | Any` is not equivalent to `int`, since there are many possible materializations of
`bool | Any` that are not assignable to `int`. It is therefore _not_ necessary for `X` to be
gradually equivalent to `Y` in order for `Foo[X]` to be assignable to `Foo[Y]`; it is _only_
necessary for `X` and `Y` to be mutually assignable.

```py
from typing import Any, TypeVar, Generic
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to

InvariantTypeVar = TypeVar("InvariantTypeVar")

class Foo(Generic[InvariantTypeVar]):
    x: InvariantTypeVar

class A: ...
class B(A): ...
class C: ...

static_assert(is_assignable_to(Foo[A], Foo[B | Any]))
static_assert(is_assignable_to(Foo[B | Any], Foo[A]))
static_assert(is_assignable_to(Foo[Foo[Any]], Foo[Foo[A | C]]))
static_assert(is_assignable_to(Foo[Foo[A | C]], Foo[Foo[Any]]))
static_assert(is_assignable_to(Foo[tuple[A]], Foo[tuple[Any] | tuple[B]]))
static_assert(is_assignable_to(Foo[tuple[Any] | tuple[B]], Foo[tuple[A]]))

def f(obj: Foo[A]):
    g(obj)

def g(obj: Foo[B | Any]):
    f(obj)

def f2(obj: Foo[Foo[Any]]):
    g2(obj)

def g2(obj: Foo[Foo[A | C]]):
    f2(obj)

def f3(obj: Foo[tuple[Any] | tuple[B]]):
    g3(obj)

def g3(obj: Foo[tuple[A]]):
    f3(obj)
```

## Generic aliases

```py
from typing import final
from ty_extensions import static_assert
from ty_extensions._internal import TypeOf, is_assignable_to

class GenericClass[T]:
    x: T  # invariant

static_assert(is_assignable_to(TypeOf[GenericClass], type[GenericClass]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[GenericClass[int]], type[GenericClass]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[GenericClass], type[GenericClass[int]]))
static_assert(is_assignable_to(TypeOf[GenericClass[int]], type[GenericClass[int]]))
static_assert(not is_assignable_to(TypeOf[GenericClass[str]], type[GenericClass[int]]))

class GenericClassIntBound[T: int]:
    x: T  # invariant

static_assert(is_assignable_to(TypeOf[GenericClassIntBound], type[GenericClassIntBound]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[GenericClassIntBound[int]], type[GenericClassIntBound]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[GenericClassIntBound], type[GenericClassIntBound[int]]))
static_assert(is_assignable_to(TypeOf[GenericClassIntBound[int]], type[GenericClassIntBound[int]]))

@final
class GenericFinalClass[T]:
    x: T  # invariant

static_assert(is_assignable_to(TypeOf[GenericFinalClass], type[GenericFinalClass]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[GenericFinalClass[int]], type[GenericFinalClass]))  # error: [missing-type-argument]
static_assert(is_assignable_to(TypeOf[GenericFinalClass], type[GenericFinalClass[int]]))
static_assert(is_assignable_to(TypeOf[GenericFinalClass[int]], type[GenericFinalClass[int]]))
static_assert(not is_assignable_to(TypeOf[GenericFinalClass[str]], type[GenericFinalClass[int]]))
```

## `TypeGuard` and `TypeIs`

`TypeGuard[...]` and `TypeIs[...]` are always assignable to `bool`.

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, is_assignable_to
from typing_extensions import Any, TypeGuard, TypeIs

static_assert(is_assignable_to(TypeGuard[Unknown], bool))
static_assert(is_assignable_to(TypeIs[Any], bool))

static_assert(not is_assignable_to(TypeGuard[Unknown], str))
static_assert(not is_assignable_to(TypeIs[Any], str))
```

## `TypeIs` with gradual types

`TypeIs` is invariant in its declared type. But gradual types are assignable to and from any type,
so `TypeIs` annotations that differ only by `Any` are still compatible:

```py
from collections.abc import Sequence
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing_extensions import Any, TypeIs

static_assert(is_assignable_to(TypeIs[Sequence[int]], TypeIs[Sequence[Any]]))
static_assert(is_assignable_to(TypeIs[Sequence[Any]], TypeIs[Sequence[int]]))
static_assert(not is_assignable_to(TypeIs[Sequence[int]], TypeIs[Sequence[object]]))
```

## `callable` as a `TypeIs` predicate

The runtime predicate type and the declared `TypeIs` type are related but distinct. The builtin
`callable` predicate can be used where a predicate for `Callable[..., Any]` is expected:

```py
from collections.abc import Callable
from typing import Any
from typing_extensions import TypeIs

Plugin = Callable[..., Any]
IsPlugin = Callable[[object], TypeIs[Plugin]]

def accepts_plugin_predicate(plugin_type: IsPlugin = callable) -> None:
    pass

def takes_plugin_predicate(plugin_type: IsPlugin) -> None:
    pass

takes_plugin_predicate(callable)
```

## `ParamSpec`

```py
from ty_extensions import static_assert
from ty_extensions._internal import Unknown, TypeOf, is_assignable_to
from typing import ParamSpec, Mapping, Callable, Any

P = ParamSpec("P")

def f(func: Callable[P, int], *args: P.args, **kwargs: P.kwargs) -> None:
    static_assert(is_assignable_to(TypeOf[args], tuple[Any, ...]))
    static_assert(is_assignable_to(TypeOf[args], tuple[object, ...]))
    static_assert(is_assignable_to(TypeOf[args], tuple[Unknown, ...]))
    static_assert(not is_assignable_to(TypeOf[args], tuple[int, ...]))
    static_assert(not is_assignable_to(TypeOf[args], tuple[int, str]))

    static_assert(not is_assignable_to(tuple[Any, ...], TypeOf[args]))
    static_assert(not is_assignable_to(tuple[object, ...], TypeOf[args]))
    static_assert(not is_assignable_to(tuple[Unknown, ...], TypeOf[args]))

    static_assert(is_assignable_to(TypeOf[kwargs], dict[str, Any]))
    static_assert(is_assignable_to(TypeOf[kwargs], dict[str, Unknown]))
    static_assert(not is_assignable_to(TypeOf[kwargs], dict[str, object]))
    static_assert(not is_assignable_to(TypeOf[kwargs], dict[str, int]))
    static_assert(is_assignable_to(TypeOf[kwargs], Mapping[str, Any]))
    static_assert(is_assignable_to(TypeOf[kwargs], Mapping[str, object]))
    static_assert(is_assignable_to(TypeOf[kwargs], Mapping[str, Unknown]))

    static_assert(not is_assignable_to(dict[str, Any], TypeOf[kwargs]))
    static_assert(not is_assignable_to(dict[str, object], TypeOf[kwargs]))
    static_assert(not is_assignable_to(dict[str, Unknown], TypeOf[kwargs]))
```

## `Concatenate`

### Self-assignability

A `Callable` with `Concatenate` should be assignable to itself.

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate

static_assert(is_assignable_to(Callable[Concatenate[int, ...], None], Callable[Concatenate[int, ...], None]))
static_assert(is_assignable_to(Callable[Concatenate[int, str, ...], None], Callable[Concatenate[int, str, ...], None]))
```

### Assignable to gradual callable

A callable with `Concatenate` parameters should be assignable to the gradual callable form, since
the gradual form is consistent with any input signature.

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate

static_assert(is_assignable_to(Callable[Concatenate[int, ...], None], Callable[..., None]))
static_assert(is_assignable_to(Callable[Concatenate[int, str, ...], None], Callable[..., None]))
```

And the gradual callable should also be assignable to one with `Concatenate` parameters.

```py
static_assert(is_assignable_to(Callable[..., None], Callable[Concatenate[int, ...], None]))
static_assert(is_assignable_to(Callable[..., None], Callable[Concatenate[int, str, ...], None]))
```

### Assignable from bottom callable

```py
from ty_extensions import static_assert
from ty_extensions._internal import RegularCallableTypeOf, is_assignable_to
from typing import Callable, Concatenate, Never

def bottom(*args: object, **kwargs: object) -> Never:
    raise NotImplementedError

static_assert(is_assignable_to(RegularCallableTypeOf[bottom], Callable[Concatenate[int, ...], None]))
static_assert(is_assignable_to(RegularCallableTypeOf[bottom], Callable[Concatenate[int, str, ...], None]))

static_assert(not is_assignable_to(Callable[Concatenate[int, ...], None], RegularCallableTypeOf[bottom]))
static_assert(not is_assignable_to(Callable[Concatenate[int, str, ...], None], RegularCallableTypeOf[bottom]))
```

### Contravariance of parameters

Callable parameters are contravariant: a callable accepting a wider type (`A`) is assignable to one
expecting a narrower type (`B`), because any call valid for `B` is also valid for `A`.

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate

class Parent: ...
class Child(Parent): ...

static_assert(is_assignable_to(Callable[Concatenate[Parent, ...], None], Callable[Concatenate[Child, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[Child, ...], None], Callable[Concatenate[Parent, ...], None]))
```

### Different parameter types

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate, final

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

static_assert(not is_assignable_to(Callable[Concatenate[A, ...], None], Callable[Concatenate[B, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[B, ...], None], Callable[Concatenate[A, ...], None]))
```

### Different number of prepended parameters

Callables with different numbers of prepended parameters should be assignable.

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate

static_assert(is_assignable_to(Callable[Concatenate[int, ...], None], Callable[Concatenate[int, str, ...], None]))
static_assert(is_assignable_to(Callable[Concatenate[int, str, ...], None], Callable[Concatenate[int, ...], None]))
```

### `Concatenate` with ellipsis vs explicit parameter list

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate

static_assert(is_assignable_to(Callable[Concatenate[int, ...], None], Callable[[int], None]))
static_assert(is_assignable_to(Callable[[int], None], Callable[Concatenate[int, ...], None]))

static_assert(is_assignable_to(Callable[Concatenate[int, ...], None], Callable[[int, str], None]))
static_assert(is_assignable_to(Callable[[int, str], None], Callable[Concatenate[int, ...], None]))
```

### `Concatenate` with `ParamSpec`

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_assignable_to
from typing import Callable, Concatenate

class A: ...

def with_paramspec[**P](_: Callable[P, None]):
    static_assert(is_assignable_to(Callable[Concatenate[int, P], None], Callable[..., None]))
    static_assert(is_assignable_to(Callable[..., None], Callable[Concatenate[int, P], None]))
```

### Gradual `Concatenate` with regular function

```py
from ty_extensions import static_assert
from ty_extensions._internal import RegularCallableTypeOf, is_assignable_to
from typing import Callable, Concatenate

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

A `Concatenate` form that ends with `...` means that all of the parameters before `...` are
positional-only.

```py
def positional_only(a: A, b: B, /) -> None: ...
def with_default(a: A, b: B = B(), /) -> None: ...

static_assert(is_assignable_to(RegularCallableTypeOf[positional_only], Callable[Concatenate[A, ...], None]))
static_assert(is_assignable_to(Callable[Concatenate[A, ...], None], RegularCallableTypeOf[positional_only]))

static_assert(is_assignable_to(RegularCallableTypeOf[positional_only], Callable[Concatenate[A, B, ...], None]))
static_assert(is_assignable_to(Callable[Concatenate[A, B, ...], None], RegularCallableTypeOf[positional_only]))

# Concatenate has an additional required positional-only parameter which isn't present in the
# function definition, so they aren't assignable.
static_assert(not is_assignable_to(RegularCallableTypeOf[positional_only], Callable[Concatenate[A, B, C, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, B, C, ...], None], RegularCallableTypeOf[positional_only]))

static_assert(is_assignable_to(RegularCallableTypeOf[with_default], Callable[Concatenate[A, ...], None]))
static_assert(is_assignable_to(Callable[Concatenate[A, ...], None], RegularCallableTypeOf[with_default]))

# For an optional parameter (with default value), it is assignable to a non-optional parameter, but
# the reverse is not true.
static_assert(is_assignable_to(RegularCallableTypeOf[with_default], Callable[Concatenate[A, B, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, B, ...], None], RegularCallableTypeOf[with_default]))
```

But, a regular callable can contain a positional-or-keyword parameter which is sometimes compatible
with the `Concatenate` with gradual form.

```py
def positional_or_keyword(a: A, b: B) -> None: ...

static_assert(is_assignable_to(RegularCallableTypeOf[positional_or_keyword], Callable[Concatenate[A, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, ...], None], RegularCallableTypeOf[positional_or_keyword]))

static_assert(is_assignable_to(RegularCallableTypeOf[positional_or_keyword], Callable[Concatenate[A, B, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, B, ...], None], RegularCallableTypeOf[positional_or_keyword]))
```

For variadic parameter, it is assignable only when the type of the variadic parameter is compatible
with the type of all the prefix parameters in the `Concatenate` form.

```py
def variadic_a(*args: A) -> None: ...
def variadic_b(*args: B) -> None: ...

static_assert(is_assignable_to(RegularCallableTypeOf[variadic_a], Callable[Concatenate[A, ...], None]))
static_assert(is_assignable_to(RegularCallableTypeOf[variadic_a], Callable[Concatenate[A, A, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, ...], None], RegularCallableTypeOf[variadic_a]))

static_assert(not is_assignable_to(RegularCallableTypeOf[variadic_a], Callable[Concatenate[A, B, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, B, ...], None], RegularCallableTypeOf[variadic_a]))

static_assert(not is_assignable_to(RegularCallableTypeOf[variadic_b], Callable[Concatenate[A, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, ...], None], RegularCallableTypeOf[variadic_b]))
```

For all the other parameter kinds, it is not assignable in either direction.

```py
def keyword_only(*, a: A, b: B) -> None: ...
def keyword_variadic(**kwargs: A) -> None: ...

static_assert(not is_assignable_to(RegularCallableTypeOf[keyword_only], Callable[Concatenate[A, B, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, B, ...], None], RegularCallableTypeOf[keyword_only]))

static_assert(not is_assignable_to(RegularCallableTypeOf[keyword_variadic], Callable[Concatenate[A, ...], None]))
static_assert(not is_assignable_to(Callable[Concatenate[A, ...], None], RegularCallableTypeOf[keyword_variadic]))
```

[gradual form]: https://typing.python.org/en/latest/spec/glossary.html#term-gradual-form
[gradual tuple]: https://typing.python.org/en/latest/spec/tuples.html#tuple-type-form
[typing documentation]: https://typing.python.org/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
