Skip to content

Commit 8c989bf

Browse files
carljmgvanrossum
authored andcommitted
Allow NewType subclassing NewType. (#3465)
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").
1 parent 166d54d commit 8c989bf

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

mypy/semanal.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,10 +1822,6 @@ def check_newtype_args(self, name: str, call: CallExpr, context: Context) -> Opt
18221822
return None
18231823
old_type = self.anal_type(unanalyzed_type)
18241824

1825-
if isinstance(old_type, Instance) and old_type.type.is_newtype:
1826-
self.fail("Argument 2 to NewType(...) cannot be another NewType", context)
1827-
has_failed = True
1828-
18291825
return None if has_failed else old_type
18301826

18311827
def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance) -> TypeInfo:

test-data/unit/check-newtype.test

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,29 @@ y = Bar2(42)
155155
y = func3(x)
156156
[out]
157157

158+
[case testNewTypeWithNewType]
159+
from typing import NewType
160+
A = NewType('A', int)
161+
B = NewType('B', A)
162+
C = A
163+
D = C
164+
E = NewType('E', D)
165+
166+
a = A(1)
167+
b = B(a)
168+
e = E(a)
169+
170+
def funca(a: A) -> None: ...
171+
def funcb(b: B) -> None: ...
172+
173+
funca(a)
174+
funca(b)
175+
funca(e)
176+
funcb(a) # E: Argument 1 to "funcb" has incompatible type "A"; expected "B"
177+
funcb(b)
178+
funcb(e) # E: Argument 1 to "funcb" has incompatible type "E"; expected "B"
179+
180+
[out]
158181

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

@@ -279,15 +302,6 @@ main:3: error: Argument 2 to NewType(...) must be subclassable (got T?)
279302
main:3: error: Invalid type "__main__.T"
280303
main:4: error: Invalid type "__main__.T"
281304

282-
[case testNewTypeWithNewTypeFails]
283-
from typing import NewType
284-
A = NewType('A', int)
285-
B = NewType('B', A) # E: Argument 2 to NewType(...) cannot be another NewType
286-
C = A
287-
D = C
288-
E = NewType('E', D) # E: Argument 2 to NewType(...) cannot be another NewType
289-
[out]
290-
291305
[case testNewTypeRedefiningVariablesFails]
292306
from typing import NewType
293307

0 commit comments

Comments
 (0)