# Tests for invalid types in type expressions

## Invalid types are rejected

Many types are illegal in the context of a type expression:

```py
import typing
from ty_extensions import AlwaysTruthy, AlwaysFalsy
from typing_extensions import Literal, Never

class A: ...

def _(
    a: type[int],
    b: AlwaysTruthy,
    c: AlwaysFalsy,
    d: Literal[True],
    e: Literal["bar"],
    f: Literal[b"foo"],
    g: tuple[int, str],
    h: Never,
    i: int,
    j: A,
):
    def foo(): ...
    def invalid(
        a_: a,  # error: [invalid-type-form] "Variable of type `type[int]` is not allowed in a parameter annotation"
        b_: b,  # error: [invalid-type-form]
        c_: c,  # error: [invalid-type-form]
        d_: d,  # error: [invalid-type-form]
        e_: e,  # error: [invalid-type-form]
        f_: f,  # error: [invalid-type-form]
        g_: g,  # error: [invalid-type-form]
        h_: h,  # error: [invalid-type-form]
        i_: typing,  # error: [invalid-type-form]
        j_: foo,  # error: [invalid-type-form]
        k_: i,  # error: [invalid-type-form] "Variable of type `int` is not allowed in a parameter annotation"
        l_: j,  # error: [invalid-type-form] "Variable of type `A` is not allowed in a parameter annotation"
    ):
        reveal_type(a_)  # revealed: Unknown
        reveal_type(b_)  # revealed: Unknown
        reveal_type(c_)  # revealed: Unknown
        reveal_type(d_)  # revealed: Unknown
        reveal_type(e_)  # revealed: Unknown
        reveal_type(f_)  # revealed: Unknown
        reveal_type(g_)  # revealed: Unknown
        reveal_type(h_)  # revealed: Unknown
        reveal_type(i_)  # revealed: Unknown
        reveal_type(j_)  # revealed: Unknown

# Inspired by the conformance test suite at
# https://github.com/python/typing/blob/d4f39b27a4a47aac8b6d4019e1b0b5b3156fabdc/conformance/tests/aliases_implicit.py#L88-L122
B = [x for x in range(42)]
C = {x for x in range(42)}
D = {x: y for x, y in enumerate(range(42))}
E = (x for x in range(42))

def _(
    b: B,  # error: [invalid-type-form]
    c: C,  # error: [invalid-type-form]
    d: D,  # error: [invalid-type-form]
    e: E,  # error: [invalid-type-form]
):
    reveal_type(b)  # revealed: Unknown
    reveal_type(c)  # revealed: Unknown
    reveal_type(d)  # revealed: Unknown
    reveal_type(e)  # revealed: Unknown
```

## Invalid AST nodes

```py
from typing import TypeVar

T = TypeVar("T")

def bar() -> None:
    return None

def outer_sync():  # `yield` from is only valid syntax inside a synchronous function
    def _(
        a: (yield from [1]),  # error: [invalid-type-form] "`yield from` expressions are not allowed in parameter annotations"
    ): ...

async def baz(): ...
async def outer_async():  # avoid unrelated syntax errors on `yield` and `await`
    def _(
        a: 1,  # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
        b: 2.3,  # error: [invalid-type-form] "Float literals are not allowed in parameter annotations"
        c: 4j,  # error: [invalid-type-form] "Complex literals are not allowed in parameter annotations"
        d: True,  # error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
        # error: [unsupported-operator]
        # error: [invalid-type-form] "Bytes literals are not allowed in this context in a parameter annotation"
        e: int | b"foo",
        f: 1 and 2,  # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
        g: 1 or 2,  # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
        h: (foo := 1),  # error: [invalid-type-form] "Named expressions are not allowed in parameter annotations"
        i: not 1,  # error: [invalid-type-form] "Unary operations are not allowed in parameter annotations"
        j: lambda: 1,  # error: [invalid-type-form] "`lambda` expressions are not allowed in parameter annotations"
        k: 1 if True else 2,  # error: [invalid-type-form] "`if` expressions are not allowed in parameter annotations"
        l: await baz(),  # error: [invalid-type-form] "`await` expressions are not allowed in parameter annotations"
        m: (yield 1),  # error: [invalid-type-form] "`yield` expressions are not allowed in parameter annotations"
        n: 1 < 2,  # error: [invalid-type-form] "Comparison expressions are not allowed in parameter annotations"
        o: bar(),  # error: [invalid-type-form] "Function calls are not allowed in parameter annotations"
        # error: [unsupported-operator]
        # error: [invalid-type-form] "F-strings are not allowed in parameter annotations"
        p: int | f"foo",
        # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
        q: [1, 2, 3][1:2],
        # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
        r: list[T][int],
        # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
        s: list[list[T][int]],
    ):
        reveal_type(a)  # revealed: Unknown
        reveal_type(b)  # revealed: Unknown
        reveal_type(c)  # revealed: Unknown
        reveal_type(d)  # revealed: Unknown
        reveal_type(e)  # revealed: int | Unknown
        reveal_type(f)  # revealed: Unknown
        reveal_type(g)  # revealed: Unknown
        reveal_type(h)  # revealed: Unknown
        reveal_type(i)  # revealed: Unknown
        reveal_type(j)  # revealed: Unknown
        reveal_type(k)  # revealed: Unknown
        reveal_type(l)  # revealed: Unknown
        reveal_type(m)  # revealed: Unknown
        reveal_type(n)  # revealed: Unknown
        reveal_type(o)  # revealed: Unknown
        reveal_type(p)  # revealed: int | Unknown
        reveal_type(q)  # revealed: Unknown

class Mat:
    def __init__(self, value: int):
        self.value = value

    def __matmul__(self, other) -> int:
        return 42

def invalid_binary_operators(
    a: "1" + "2",  # error: [invalid-type-form] "Invalid binary operator `+` in type annotation"
    b: 3 - 5.0,  # error: [invalid-type-form] "Invalid binary operator `-` in type annotation"
    c: 4 * -2,  # error: [invalid-type-form] "Invalid binary operator `*` in type annotation"
    d: Mat(4) @ Mat(2),  # error: [invalid-type-form] "Invalid binary operator `@` in type annotation"
    e: 10 / 2,  # error: [invalid-type-form] "Invalid binary operator `/` in type annotation"
    f: 10 % 3,  # error: [invalid-type-form] "Invalid binary operator `%` in type annotation"
    g: 2**-0.5,  # error: [invalid-type-form] "Invalid binary operator `**` in type annotation"
    h: 10 // 3,  # error: [invalid-type-form] "Invalid binary operator `//` in type annotation"
    i: 1 << 2,  # error: [invalid-type-form] "Invalid binary operator `<<` in type annotation"
    j: 4 >> 42,  # error: [invalid-type-form] "Invalid binary operator `>>` in type annotation"
    k: 5 ^ 3,  # error: [invalid-type-form] "Invalid binary operator `^` in type annotation"
    l: 5 & 3,  # error: [invalid-type-form] "Invalid binary operator `&` in type annotation"
):
    reveal_type(a)  # revealed: Unknown
    reveal_type(b)  # revealed: Unknown
    reveal_type(c)  # revealed: Unknown
    reveal_type(d)  # revealed: Unknown
    reveal_type(e)  # revealed: Unknown
    reveal_type(f)  # revealed: Unknown
    reveal_type(g)  # revealed: Unknown
    reveal_type(h)  # revealed: Unknown
    reveal_type(i)  # revealed: Unknown
    reveal_type(j)  # revealed: Unknown
    reveal_type(k)  # revealed: Unknown
    reveal_type(l)  # revealed: Unknown
```

## Error recovery upon encountering invalid AST nodes

Upon encountering an invalid-in-type-expression AST node, we try to avoid cascading diagnostics. For
example, in this snippet, we only report the the outer list literal is invalid, and ignore the fact
that there is also an invalid list literal inside the outer list literal node:

```py
# error: [invalid-type-form]
x: [[int]]
```

However, runtime errors inside invalid AST nodes are still reported -- these errors are more serious
than just "typing spec pedantry":

```py
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
# error: [unresolved-reference] "Name `foo` used when not defined"
x: [[foo]]
```

But we avoid false-positive diagnostics regarding unresolved references inside string annotations if
we detect that the string annotation is an invalid type form. These diagnostics would just add
noise, since stringized annotations are never executed at runtime. The following snippet causes us
to emit `invalid-type-form`, but we ignore that `foo` is an "unresolved reference" inside the string
annotation:

```py
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
x: "[[foo]]"
```

## Multiple starred expressions in a `tuple` specialization

<!-- snapshot-diagnostics -->

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

```py
from typing import TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")

def f(
    # error: [invalid-type-form] "Multiple unpacked variadic tuples are not allowed in a `tuple` specialization"
    x: tuple[*tuple[int, ...], *tuple[str, ...]],
    # error: [invalid-type-form] "Multiple unpacked variadic tuples are not allowed in a `tuple` specialization"
    x2: tuple[Unpack[tuple[int, ...]], Unpack[tuple[str, ...]]],
    y: tuple[*tuple[int, ...], str, int, *tuple[str, ...]],  # error: [invalid-type-form]
    y2: tuple[Unpack[tuple[int, ...]], str, int, Unpack[tuple[str, ...]]],  # error: [invalid-type-form]
    # Multiple unpacked elements are fine, as long as the unpacked elements are not variadic:
    z: tuple[*tuple[int, ...], *tuple[str]],
    z2: tuple[Unpack[tuple[int, ...]], Unpack[tuple[str]]],
):
    reveal_type(x)  # revealed: tuple[int | str, ...]
    reveal_type(x2)  # revealed: tuple[int | str, ...]
    reveal_type(y)  # revealed: tuple[str | int, ...]
    reveal_type(y2)  # revealed: tuple[str | int, ...]
    reveal_type(z)  # revealed: tuple[*tuple[int, ...], str]
    reveal_type(z2)  # revealed: tuple[*tuple[int, ...], str]

T1 = tuple[int, *Ts, str, *Ts]  # error: [invalid-type-form]

def func3(t: tuple[*Ts]):
    t5: tuple[*tuple[str], *Ts]  # OK
    t6: tuple[*tuple[str, ...], *Ts]  # error: [invalid-type-form]
```

## Ellipses in the wrong place in a `tuple` specialization

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

```py
t1: tuple[int, ...]
# error: [invalid-type-form] "Invalid `tuple` specialization: `...` can only be used as the second element in a two-element `tuple` specialization"
t2: tuple[int, int, ...]
# error: [invalid-type-form] "Invalid `tuple` specialization: `...` can only be used as the second element in a two-element `tuple` specialization"
t3: tuple[...]
# error: [invalid-type-form] "Invalid `tuple` specialization: `...` can only be used as the second element in a two-element `tuple` specialization"
t4: tuple[..., int]
# error: [invalid-type-form] "Invalid `tuple` specialization: `...` can only be used as the second element in a two-element `tuple` specialization"
t5: tuple[int, ..., int]
# error: [invalid-type-form] "Invalid `tuple` specialization: `...` cannot be used after an unpacked element"
t6: tuple[*tuple[str], ...]
# error: [invalid-type-form] "Invalid `tuple` specialization: `...` cannot be used after an unpacked element"
t7: tuple[*tuple[str, ...], ...]
```

## Invalid AST nodes in string annotations

Invalid AST nodes should also be rejected when they appear in string annotations:

```py
def bar() -> None:
    return None

async def baz(): ...
async def outer_async():  # avoid unrelated syntax errors on `yield` and `await`
    def _(
        a: "1",  # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
        b: "2.3",  # error: [invalid-type-form] "Float literals are not allowed in parameter annotations"
        c: "4j",  # error: [invalid-type-form] "Complex literals are not allowed in parameter annotations"
        d: "True",  # error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
        e: "1 and 2",  # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
        f: "1 or 2",  # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
        g: "(foo := 1)",  # error: [invalid-type-form] "Named expressions are not allowed in parameter annotations"
        h: "not 1",  # error: [invalid-type-form] "Unary operations are not allowed in parameter annotations"
        i: "lambda: 1",  # error: [invalid-type-form] "`lambda` expressions are not allowed in parameter annotations"
        j: "1 if True else 2",  # error: [invalid-type-form] "`if` expressions are not allowed in parameter annotations"
        k: "await baz()",  # error: [invalid-type-form] "`await` expressions are not allowed in parameter annotations"
        l: "(yield 1)",  # error: [invalid-type-form] "`yield` expressions are not allowed in parameter annotations"
        m: "1 < 2",  # error: [invalid-type-form] "Comparison expressions are not allowed in parameter annotations"
        n: "bar()",  # error: [invalid-type-form] "Function calls are not allowed in parameter annotations"
        # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
        o: "[1, 2, 3][1:2]",
        # error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in parameter annotations"
        p: list[int].append,
        # error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in parameter annotations"
        q: list[list[int].append],
    ):
        reveal_type(a)  # revealed: Unknown
        reveal_type(b)  # revealed: Unknown
        reveal_type(c)  # revealed: Unknown
        reveal_type(d)  # revealed: Unknown
        reveal_type(e)  # revealed: Unknown
        reveal_type(f)  # revealed: Unknown
        reveal_type(g)  # revealed: Unknown
        reveal_type(h)  # revealed: Unknown
        reveal_type(i)  # revealed: Unknown
        reveal_type(j)  # revealed: Unknown
        reveal_type(k)  # revealed: Unknown
        reveal_type(l)  # revealed: Unknown
        reveal_type(m)  # revealed: Unknown
        reveal_type(n)  # revealed: Unknown
        reveal_type(o)  # revealed: Unknown
        reveal_type(p)  # revealed: Unknown
        reveal_type(q)  # revealed: list[Unknown]
```

## Invalid Collection based AST nodes

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

```py
def _(
    a: {1: 2},  # error: [invalid-type-form] "Dict literals are not allowed in parameter annotations"
    b: {1, 2},  # error: [invalid-type-form] "Set literals are not allowed in parameter annotations"
    c: {k: v for k, v in [(1, 2)]},  # error: [invalid-type-form] "Dict comprehensions are not allowed in parameter annotations"
    d: [k for k in [1, 2]],  # error: [invalid-type-form] "List comprehensions are not allowed in parameter annotations"
    e: {k for k in [1, 2]},  # error: [invalid-type-form] "Set comprehensions are not allowed in parameter annotations"
    f: (k for k in [1, 2]),  # error: [invalid-type-form] "Generator expressions are not allowed in parameter annotations"
    # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
    g: [int, str],
    # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation: Did you mean `tuple[int, str]`?"
    h: (int, str),
    i: (),  # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation: Did you mean `tuple[()]`?"
):
    reveal_type(a)  # revealed: Unknown
    reveal_type(b)  # revealed: Unknown
    reveal_type(c)  # revealed: Unknown
    reveal_type(d)  # revealed: Unknown
    reveal_type(e)  # revealed: Unknown
    reveal_type(f)  # revealed: Unknown
    reveal_type(g)  # revealed: Unknown
    reveal_type(h)  # revealed: Unknown
    reveal_type(i)  # revealed: Unknown

# error: [invalid-type-form] "List literals are not allowed in this context in a type expression: Did you mean `list[int]`?"
class name_0[name_2: [int]]:
    pass

# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
class name_4[name_1: [{}]]:
    pass
```

## Diagnostics for common errors

<!-- snapshot-diagnostics -->

### Module-literal used when you meant to use a class from that module

It's pretty common in Python to accidentally use a module-literal type in a type expression when you
*meant* to use a class by the same name that comes from that module. We emit a nice subdiagnostic
for this case:

`foo.py`:

```py
import datetime

def f(x: datetime): ...  # error: [invalid-type-form]
```

`PIL/Image.py`:

```py
class Image: ...
```

`bar.py`:

```py
from PIL import Image

def g(x: Image): ...  # error: [invalid-type-form]
```

### List-literal used when you meant to use a list

```py
def _(
    x: [int],  # error: [invalid-type-form]
) -> [int]:  # error: [invalid-type-form]
    return x

# No special hints for these: it's unclear what the user meant:
def _(
    x: [int, str],  # error: [invalid-type-form]
) -> [int, str]:  # error: [invalid-type-form]
    return x
```

### Tuple-literal used when you meant to use a tuple

```py
def _(
    x: (),  # error: [invalid-type-form]
) -> ():  # error: [invalid-type-form]
    return x
```

```py
def _(
    x: (int,),  # error: [invalid-type-form]
) -> (int,):  # error: [invalid-type-form]
    return x
```

```py
def _(
    x: (int, str),  # error: [invalid-type-form]
) -> (int, str):  # error: [invalid-type-form]
    return x
```

### Dict-literal or set-literal when you meant to use `dict[]`/`set[]`

```py
def _(
    x: {int: str},  # error: [invalid-type-form]
    y: {str},  # error: [invalid-type-form]
): ...
```

### Special-cased diagnostic for `callable` used in a type expression

```py
# error: [invalid-type-form]
# error: [invalid-type-form]
def decorator(fn: callable) -> callable:
    return fn
```

### AST nodes that are only valid inside `Literal`

```py
def bad(
    # error: [invalid-type-form]
    a: 42,
    # error: [invalid-type-form]
    b: b"42",
    # error: [invalid-type-form]
    c: True,
    # error: [invalid-syntax-in-forward-annotation]
    d: "invalid syntax",
): ...
```
