"""Test type parameters and aliases"""

# Type parameters in type alias statements

from some_module import Bar

type Foo[T] = T # OK
type Foo[T] = list[T] # OK
type Foo[T: ForwardA] = T # OK
type Foo[*Ts] = Bar[Ts] # OK
type Foo[**P] = Bar[P] # OK
class ForwardA: ...

# Types used in aliased assignment must exist

type Foo = DoesNotExist  # F821: Undefined name `DoesNotExist`
type Foo = list[DoesNotExist]  # F821: Undefined name `DoesNotExist`

# Type parameters do not escape alias scopes

type Foo[T] = T
T  # F821: Undefined name `T` - not accessible afterward alias scope

# Type parameters in functions

def foo[T](t: T) -> T: return t  # OK
async def afoo[T](t: T) -> T: return t  # OK
def with_forward_ref[T: ForwardB](t: T) -> T: return t  # OK
def can_access_inside[T](t: T) -> T:  # OK
    print(T)  # OK
    return t  # OK
class ForwardB: ...


# Type parameters do not escape function scopes

from some_library import some_decorator

@some_decorator(T)  # F821: Undefined name `T` - not accessible in decorators

def foo[T](t: T) -> None: ...
T  # F821: Undefined name `T` - not accessible afterward function scope


# Type parameters in classes

class Foo[T](list[T]): ... # OK
class UsesForward[T: ForwardC](list[T]): ...    # OK
class ForwardC: ...
class WithinBody[T](list[T]):   # OK
    t = T   # OK
    x: T  # OK

    def foo(self, x: T) -> T:  # OK
        return x

    def foo(self):
        T  # OK


# Type parameters do not escape class scopes

from some_library import some_decorator
@some_decorator(T)  # F821: Undefined name `T` - not accessible in decorators

class Foo[T](list[T]): ...
T  # F821: Undefined name `T` - not accessible after class scope

# Types specified in bounds should exist

type Foo[T: DoesNotExist] = T  # F821: Undefined name `DoesNotExist`
def foo[T: DoesNotExist](t: T) -> T: return t  # F821: Undefined name `DoesNotExist`
class Foo[T: DoesNotExist](list[T]): ...  # F821: Undefined name `DoesNotExist`

type Foo[T: (DoesNotExist1, DoesNotExist2)] = T  # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
def foo[T: (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t  # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
class Foo[T: (DoesNotExist1, DoesNotExist2)](list[T]): ...  # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`

# Same in defaults

type Foo[T = DoesNotExist] = T  # F821: Undefined name `DoesNotExist`
def foo[T = DoesNotExist](t: T) -> T: return t  # F821: Undefined name `DoesNotExist`
class Foo[T = DoesNotExist](list[T]): ...  # F821: Undefined name `DoesNotExist`

type Foo[T = (DoesNotExist1, DoesNotExist2)] = T  # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
def foo[T = (DoesNotExist1, DoesNotExist2)](t: T) -> T: return t  # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`
class Foo[T = (DoesNotExist1, DoesNotExist2)](list[T]): ...  # F821: Undefined name `DoesNotExist1`, Undefined name `DoesNotExist2`

# Type parameters in nested classes

class Parent[T]:
    t = T   # OK

    def can_use_class_variable(self, x: t) -> t:  # OK
        return x

    class Child:
        def can_access_parent_type_parameter(self, x: T) -> T:  # OK
            T  # OK
            return x

        def cannot_access_parent_variable(self, x: t) -> t:  # F821: Undefined name `T`
                t # F821: Undefined name `t`
                return x

# Type parameters in nested functions

def can_access_inside_nested[T](t: T) -> T:  # OK
    def bar(x: T) -> T:  # OK
        T # OK
        return x

    bar(t)


def cannot_access_in_default[T](t: T = T):  # F821
    pass
