-- Checks NewType(...)

-- Checks for basic functionality

[case testNewTypePEP484Example1]
from typing import NewType

UserId = NewType('UserId', int)

def name_by_id(user_id: UserId) -> str:
    return "foo"

UserId('user')  # E: Argument 1 to "UserId" has incompatible type "str"; expected "int"
name_by_id(42)  # E: Argument 1 to "name_by_id" has incompatible type "int"; expected "UserId"
name_by_id(UserId(42))

id = UserId(5)
num = id + 1

reveal_type(id)  # E: Revealed type is '__main__.UserId'
reveal_type(num)  # E: Revealed type is 'builtins.int'
[out]

[case testNewTypePEP484Example2]
from typing import NewType

class PacketId:
    def __init__(self, major: int, minor: int) -> None:
        self._major = major
        self._minor = minor

TcpPacketId = NewType('TcpPacketId', PacketId)

packet = PacketId(100, 100)
tcp_packet = TcpPacketId(packet)
tcp_packet = TcpPacketId(127, 0)

[out]
main:12: error: Too many arguments for "TcpPacketId"
main:12: error: Argument 1 to "TcpPacketId" has incompatible type "int"; expected "PacketId"

[case testNewTypeWithTuples]
from typing import NewType, Tuple
TwoTuple = NewType('TwoTuple', Tuple[int, str])
a = TwoTuple((3, "a"))
b = TwoTuple(("a", 3))  # E: Argument 1 to "TwoTuple" has incompatible type "Tuple[str, int]"; expected "Tuple[int, str]"

reveal_type(a[0])  # E: Revealed type is 'builtins.int'
reveal_type(a[1])  # E: Revealed type is 'builtins.str'
[builtins fixtures/tuple.pyi]
[out]

[case testNewTypeWithLists]
from typing import NewType, List
UserId = NewType('UserId', int)
IdList = NewType('IdList', List[UserId])

bad1 = IdList([1])  # E: List item 0 has incompatible type "int"; expected "UserId"

foo = IdList([])
foo.append(3)  # E: Argument 1 to "append" of "list" has incompatible type "int"; expected "UserId"
foo.append(UserId(3))
foo.extend([UserId(1), UserId(2), UserId(3)])
foo.extend(IdList([UserId(1), UserId(2), UserId(3)]))
bar = IdList([UserId(2)])

baz = foo + bar
reveal_type(foo)  # E: Revealed type is '__main__.IdList'
reveal_type(bar)  # E: Revealed type is '__main__.IdList'
reveal_type(baz)  # E: Revealed type is 'builtins.list[__main__.UserId*]'

[builtins fixtures/list.pyi]
[out]

[case testNewTypeWithGenerics]
from typing import TypeVar, Generic, NewType, Any

T = TypeVar('T')

class Base(Generic[T]):
    def __init__(self, item: T) -> None:
        self.item = item

    def getter(self) -> T:
        return self.item

Derived1 = NewType('Derived1', Base[str])
Derived2 = NewType('Derived2', Base)       # Implicit 'Any'
Derived3 = NewType('Derived3', Base[Any])  # Explicit 'Any'

Derived1(Base(1))  # E: Argument 1 to "Base" has incompatible type "int"; expected "str"
Derived1(Base('a'))
Derived2(Base(1))
Derived2(Base('a'))
Derived3(Base(1))
Derived3(Base('a'))

reveal_type(Derived1(Base('a')).getter())  # E: Revealed type is 'builtins.str*'
reveal_type(Derived3(Base('a')).getter())  # E: Revealed type is 'Any'
[out]

[case testNewTypeWithNamedTuple]
from collections import namedtuple
from typing import NewType, NamedTuple

Vector1 = namedtuple('Vector1', ['x', 'y'])
Point1 = NewType('Point1', Vector1)
p1 = Point1(Vector1(1, 2))
reveal_type(p1.x)  # E: Revealed type is 'Any'
reveal_type(p1.y)  # E: Revealed type is 'Any'

Vector2 = NamedTuple('Vector2', [('x', int), ('y', int)])
Point2 = NewType('Point2', Vector2)
p2 = Point2(Vector2(1, 2))
reveal_type(p2.x)  # E: Revealed type is 'builtins.int'
reveal_type(p2.y)  # E: Revealed type is 'builtins.int'

class Vector3:
    def __init__(self, x: int, y: int) -> None:
        self.x = x
        self.y = y
Point3 = NewType('Point3', Vector3)
p3 = Point3(Vector3(1, 3))
reveal_type(p3.x)  # E: Revealed type is 'builtins.int'
reveal_type(p3.y)  # E: Revealed type is 'builtins.int'

[builtins fixtures/list.pyi]

[out]

[case testNewTypeWithCasts]
from typing import NewType, cast
UserId = NewType('UserId', int)
foo = UserId(3)
foo = cast(UserId, 3)
foo = cast(UserId, "foo")
foo = cast(UserId, UserId(4))
[out]

[case testNewTypeWithTypeAliases]
from typing import NewType
Foo = int
Bar = NewType('Bar', Foo)
Bar2 = Bar

def func1(x: Foo) -> Bar:
    return Bar(x)

def func2(x: int) -> Bar:
    return Bar(x)

def func3(x: Bar2) -> Bar:
    return x

x = Bar(42)
y = Bar2(42)

y = func3(x)
[out]

[case testNewTypeWithNewType]
from typing import NewType
A = NewType('A', int)
B = NewType('B', A)
C = A
D = C
E = NewType('E', D)

a = A(1)
b = B(a)
e = E(a)

def funca(a: A) -> None: ...
def funcb(b: B) -> None: ...

funca(a)
funca(b)
funca(e)
funcb(a)  # E: Argument 1 to "funcb" has incompatible type "A"; expected "B"
funcb(b)
funcb(e)  # E: Argument 1 to "funcb" has incompatible type "E"; expected "B"

[out]

-- Make sure NewType works as expected in a variety of different scopes/across files

[case testNewTypeInLocalScope]
from typing import NewType
A = NewType('A', int)
a = A(3)

def func() -> None:
    A = NewType('A', str)
    B = NewType('B', str)

    a = A(3)  # E: Argument 1 to "A" has incompatible type "int"; expected "str"
    a = A('xyz')
    b = B('xyz')

class MyClass:
    C = NewType('C', float)

    def foo(self) -> 'MyClass.C':
        return MyClass.C(3.2)

b = A(3)
c = MyClass.C(3.5)
[out]

[case testNewTypeInMultipleFiles]
import a
import b
list1 = [a.UserId(1), a.UserId(2)]
list1.append(b.UserId(3))  # E: Argument 1 to "append" of "list" has incompatible type "b.UserId"; expected "a.UserId"

[file a.py]
from typing import NewType
UserId = NewType('UserId', int)

[file b.py]
from typing import NewType
UserId = NewType('UserId', int)

[builtins fixtures/list.pyi]
[out]

[case testNewTypeWithIncremental]
import m

[file m.py]
from typing import NewType

UserId = NewType('UserId', int)

def name_by_id(user_id: UserId) -> str:
    return "foo"

name_by_id(UserId(42))

id = UserId(5)
num = id + 1

[file m.py.2]
from typing import NewType

UserId = NewType('UserId', int)

def name_by_id(user_id: UserId) -> str:
    return "foo"

name_by_id(UserId(42))

id = UserId(5)
num = id + 1

reveal_type(id)
reveal_type(num)
[rechecked m]
[stale]
[out1]
[out2]
tmp/m.py:13: error: Revealed type is 'm.UserId'
tmp/m.py:14: error: Revealed type is 'builtins.int'


-- Check misuses of NewType fail

[case testNewTypeBadInitializationFails]
from typing import NewType

a = NewType('b', int)  # E: String argument 1 'b' to NewType(...) does not match variable name 'a'
b = NewType('b', 3)  # E: Argument 2 to NewType(...) must be a valid type
c = NewType(2, int)  # E: Argument 1 to NewType(...) must be a string literal
foo = "d"
d = NewType(foo, int)  # E: Argument 1 to NewType(...) must be a string literal
e = NewType(name='e', tp=int)  # E: NewType(...) expects exactly two positional arguments
f = NewType('f', tp=int)  # E: NewType(...) expects exactly two positional arguments
[out]

[case testNewTypeWithAnyFails]
from typing import NewType, Any
A = NewType('A', Any)  # E: Argument 2 to NewType(...) must be subclassable (got "Any")
[out]

[case testNewTypeWithUnionsFails]
from typing import NewType, Union
Foo = NewType('Foo', Union[int, float])  # E: Argument 2 to NewType(...) must be subclassable (got "Union[int, float]")
[out]

[case testNewTypeWithTypeTypeFails]
from typing import NewType, Type
Foo = NewType('Foo', Type[int])  # E: Argument 2 to NewType(...) must be subclassable (got "Type[int]")
a = Foo(type(3))
[builtins fixtures/args.pyi]
[out]

[case testNewTypeWithTypeVarsFails]
from typing import NewType, TypeVar, List
T = TypeVar('T')
A = NewType('A', T)
B = NewType('B', List[T])
[builtins fixtures/list.pyi]
[out]
main:3: error: Argument 2 to NewType(...) must be subclassable (got T?)
main:3: error: Invalid type "__main__.T"
main:4: error: Invalid type "__main__.T"

[case testNewTypeRedefiningVariablesFails]
from typing import NewType

a = 3
a = NewType('a', int)

b = NewType('b', int)
b = NewType('b', float)  # this line throws two errors

c = NewType('c', str)   # type: str
[out]
main:4: error: Cannot redefine 'a' as a NewType
main:7: error: Cannot assign to a type
main:7: error: Cannot redefine 'b' as a NewType
main:9: error: Cannot declare the type of a NewType declaration

[case testNewTypeAddingExplicitTypesFails]
from typing import NewType
UserId = NewType('UserId', int)

a = 3  # type: UserId  # E: Incompatible types in assignment (expression has type "int", variable has type "UserId")
[out]

[case testNewTypeTestSubclassingFails]
from typing import NewType
class A: pass
B = NewType('B', A)
class C(B): pass  # E: Cannot subclass NewType
[out]

[case testCannotUseNewTypeWithProtocols]
from typing import Protocol, NewType

class P(Protocol):
    attr: int
class D:
    attr: int

C = NewType('C', P)  # E: NewType cannot be used with protocol classes

x: C = C(D())  # We still accept this, treating 'C' as non-protocol subclass.
reveal_type(x.attr)  # E: Revealed type is 'builtins.int'
x.bad_attr  # E: "C" has no attribute "bad_attr"
C(1)  # E: Argument 1 to "C" has incompatible type "int"; expected "P"
[out]

[case testNewTypeAny]
from typing import NewType
Any = NewType('Any', int)
Any(5)

[case testNewTypeAndIsInstance]
from typing import NewType
T = NewType('T', int)
d: object
if isinstance(d, T):  # E: Cannot use isinstance() with a NewType type
    reveal_type(d) # E: Revealed type is '__main__.T'
[builtins fixtures/isinstancelist.pyi]

[case testInvalidNewTypeCrash]
from typing import List, NewType, Union
N = NewType('N', XXX)  # E: Argument 2 to NewType(...) must be subclassable (got "Any") \
                       # E: Name 'XXX' is not defined
x: List[Union[N, int]]  # E: Invalid type "__main__.N"
[builtins fixtures/list.pyi]
