Skip to content

Incorrect is narrowing of code involving newtypes #3552

@AlexWaygood

Description

@AlexWaygood

Summary

We're often too eager to apply intersections when evaluating narrowing constraints created by the is operator. This leads to lots of situations involving NewTypes where ty can incorrectly infer code as being unreachable:

from typing import NewType

class Foo: ...

FooNewType1 = NewType("FooNewType1", Foo)
FooNewType2 = NewType("FooNewType2", Foo)

foo = Foo()
foo1 = FooNewType1(foo)
foo2 = FooNewType2(foo)

if foo1 is foo2:  # evaluates to `True` at runtime
    reveal_type(foo1)  # Never
    reveal_type(foo2)  # Never

BoolNewType = NewType("BoolNewType", bool)
IntNewType = NewType("IntNewType", int)
StrNewType = NewType("StrNewType", str)
BytesNewType = NewType("BytesNewType", bytes)

true = True  # has type `Literal[True]`
fourty_two = 42  # has type `Literal[42]`
some_string = 'some_string'  # has type `Literal["some_string"]`
some_bytes = b'some_bytes'  # has type `Literal[b"some_bytes"]

if BoolNewType(true) is true:  # evaluates to `True` at runtime
    reveal_type(true)  # Never

if IntNewType(fourty_two) is fourty_two:  # evaluates to `True` at runtime
    reveal_type(fourty_two)  # Never

if StrNewType(some_string) is some_string:  # evaluates to `True` at runtime
    reveal_type(some_string)  # Never

if BytesNewType(some_bytes) is some_bytes:  # evaluates to `True` at runtime
    reveal_type(some_bytes)  # Never

https://play.ty.dev/1ceb245d-d41c-454e-b628-35158ec66414

For comparison, pyrefly appears to have exactly the same bugs as ty here, but pyright/mypy/zuban/pycroscope all seem to avoid this cluster of issues. Multiplay gist: 17be90c733fd42744969a5ecd7214a78

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingnarrowingrelated to flow-sensitive type narrowing

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions