Skip to content

Commit

Permalink
Allow NewType subclassing NewType. (#3465)
Browse files Browse the repository at this point in the history
Use case: type hierarchy of IDs, all of which are integers at runtime, but we
want to type-check distinctions between e.g. "id of User" and "id of Media",
while still allowing some functions to take "any ID" (which is still a more
specific type than "any integer").
  • Loading branch information
carljm authored and gvanrossum committed May 28, 2017
1 parent 166d54d commit 8c989bf
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 13 deletions.
4 changes: 0 additions & 4 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1822,10 +1822,6 @@ def check_newtype_args(self, name: str, call: CallExpr, context: Context) -> Opt
return None
old_type = self.anal_type(unanalyzed_type)

if isinstance(old_type, Instance) and old_type.type.is_newtype:
self.fail("Argument 2 to NewType(...) cannot be another NewType", context)
has_failed = True

return None if has_failed else old_type

def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance) -> TypeInfo:
Expand Down
32 changes: 23 additions & 9 deletions test-data/unit/check-newtype.test
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,29 @@ 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

Expand Down Expand Up @@ -279,15 +302,6 @@ 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 testNewTypeWithNewTypeFails]
from typing import NewType
A = NewType('A', int)
B = NewType('B', A) # E: Argument 2 to NewType(...) cannot be another NewType
C = A
D = C
E = NewType('E', D) # E: Argument 2 to NewType(...) cannot be another NewType
[out]

[case testNewTypeRedefiningVariablesFails]
from typing import NewType

Expand Down

0 comments on commit 8c989bf

Please sign in to comment.