@@ -3726,3 +3726,103 @@ def main(
37263726 reveal_type(v_all) # N: Revealed type is "builtins.bytes | builtins.bytearray | builtins.memoryview"
37273727 reveal_type(v_memoryview) # N: Revealed type is "builtins.memoryview"
37283728[builtins fixtures/primitives.pyi]
3729+
3730+
3731+ [case testNarrowNewTypeVsSubclass]
3732+ # mypy: strict-equality, warn-unreachable
3733+ from typing import NewType
3734+
3735+ M1 = NewType("M1", int)
3736+ M2 = NewType("M2", int)
3737+
3738+ def check_m(base: int, m1: M1, m2: M2):
3739+ if m1 == m2: # E: Non-overlapping equality check (left operand type: "M1", right operand type: "M2")
3740+ reveal_type(m1) # N: Revealed type is "__main__.M1"
3741+ reveal_type(m2) # N: Revealed type is "__main__.M2"
3742+
3743+ if m1 == base:
3744+ # We do not narrow base
3745+ reveal_type(m1) # N: Revealed type is "__main__.M1"
3746+ reveal_type(base) # N: Revealed type is "builtins.int"
3747+ if m2 == base:
3748+ reveal_type(m2) # N: Revealed type is "__main__.M2"
3749+ reveal_type(base) # N: Revealed type is "builtins.int"
3750+
3751+ # We do narrow for subclasses! (assuming no custom equality)
3752+ class A: ...
3753+ class A1(A): ...
3754+ class A2(A): ...
3755+
3756+ def check_a(base: A, a1: A1, a2: A2):
3757+ if a1 == a2: # E: Non-overlapping equality check (left operand type: "A1", right operand type: "A2")
3758+ reveal_type(a1) # N: Revealed type is "__main__.A1"
3759+ reveal_type(a2) # N: Revealed type is "__main__.A2"
3760+
3761+ if a1 == base:
3762+ # We do narrow base
3763+ reveal_type(a1) # N: Revealed type is "__main__.A1"
3764+ reveal_type(base) # N: Revealed type is "__main__.A1"
3765+ if a2 == base: # E: Non-overlapping equality check (left operand type: "A2", right operand type: "A1")
3766+ reveal_type(a2) # N: Revealed type is "__main__.A2"
3767+ reveal_type(base) # N: Revealed type is "__main__.A1"
3768+ [builtins fixtures/primitives.pyi]
3769+
3770+
3771+ [case testNarrowNewTypeFromObject]
3772+ # mypy: strict-equality, warn-unreachable
3773+ from __future__ import annotations
3774+ from typing import NewType
3775+
3776+ UserId = NewType("UserId", int)
3777+
3778+ def f1(whatever: object, uid: UserId):
3779+ # The general principle is that we should not be able to produce a value of NewType
3780+ # without there being explicit wrapping somewhere
3781+ if whatever == uid:
3782+ reveal_type(whatever) # N: Revealed type is "builtins.int"
3783+ reveal_type(uid) # N: Revealed type is "__main__.UserId"
3784+
3785+ class Other: ...
3786+
3787+ def f2(whatever: object, uid: UserId | Other):
3788+ if whatever == uid:
3789+ reveal_type(whatever) # N: Revealed type is "builtins.int | __main__.Other"
3790+ reveal_type(uid) # N: Revealed type is "__main__.UserId | __main__.Other"
3791+ [builtins fixtures/primitives.pyi]
3792+
3793+
3794+ [case testNarrowNewTypeNested]
3795+ # mypy: strict-equality, warn-unreachable
3796+ from typing import NewType, Final
3797+
3798+ Path = NewType("Path", str)
3799+ NormPath = NewType("NormPath", Path)
3800+
3801+ def op(normpath: NormPath, path: Path):
3802+ if normpath == path:
3803+ # No narrowing
3804+ reveal_type(normpath) # N: Revealed type is "__main__.NormPath"
3805+ reveal_type(path) # N: Revealed type is "__main__.Path"
3806+ [builtins fixtures/primitives.pyi]
3807+
3808+
3809+ [case testNarrowNewTypeSharedValue]
3810+ # mypy: strict-equality, warn-unreachable
3811+ from typing import NewType, Final
3812+
3813+ UserId = NewType("UserId", int)
3814+ TeamId = NewType("TeamId", int)
3815+ INVALID = 123
3816+
3817+ def get_owner(uid: UserId, tid: TeamId):
3818+ # No narrowing for INVALID
3819+ if uid == INVALID:
3820+ reveal_type(uid) # N: Revealed type is "__main__.UserId"
3821+ reveal_type(tid) # N: Revealed type is "__main__.TeamId"
3822+ reveal_type(INVALID) # N: Revealed type is "builtins.int"
3823+ if tid == INVALID:
3824+ reveal_type(uid) # N: Revealed type is "__main__.UserId"
3825+ reveal_type(tid) # N: Revealed type is "__main__.TeamId"
3826+ reveal_type(INVALID) # N: Revealed type is "builtins.int"
3827+ return None
3828+ [builtins fixtures/primitives.pyi]
0 commit comments