Skip to content

--strict-equality should be disabled in functions with constrained type variables #6735

Closed

Description

@ilevkivskyi

Consider this valid code:

def foo(x: AnyStr) -> AnyStr:
    if x == '':  # False positive here
        ...
    return x

With --strict-equality this produces a "Non-overlapping equality check ...", because the function body is checked multiple times with both values of AnyStr.

Activity

  1. gvanrossum commented on Apr 27, 2019

    @gvanrossum
    Member

    Why is that a false positive? It is broken for bytes.

  2. ilevkivskyi commented on Apr 27, 2019

    @ilevkivskyi
    MemberAuthor

    It is broken for bytes.

    This flag indicates comparisons that can never be True, while this one definitely can be True.

  3. gvanrossum commented on Apr 27, 2019

    @gvanrossum
    Member

    Did this come up in a real world use case?

    The way I look at it, this flag makes comparisons more like other operators. E.g. a + 0 is invalid when a has type str. And if we have

    T = TypeVar('T', int, str)
    def foo(a: T):
        a + 0

    that's an error because for some value of T, a + 0 is a type error.

    Similarly, I expect that when we have this flag, if the function has a == 0, it would be considered an error. And hence also for AnyStr. (And in all likelihood, that example does have a bug.)

  4. ilevkivskyi commented on Apr 27, 2019

    @ilevkivskyi
    MemberAuthor

    Did this come up in a real world use case?

    Yes.

    The way I look at it, this flag makes comparisons more like other operators.

    This is a bad analogy.

    x: Union[str, int]
    x + 0  # This is clearly an error, because it can crash at runtime
    if x == 0:  # This is valid code, IMO not even questionable
        ...

    (And in all likelihood, that example does have a bug.)

    What about

    def foo(x: AnyStr) -> AnyStr:
        if x == 'special' or x == b'special':
            ...
        return x

    Mypy shows two errors here, but to me this looks perfectly OK.

  5. gvanrossum commented on Apr 27, 2019

    @gvanrossum
    Member

    I admit that the second example is more reasonable (and presumably is more like the real-world case you encountered).

    But it still feels a case of "two wrongs can make a right", and pragmatically I'd expect that such cases are outnumbered by cases where the comparison if AnyStr to a concrete str (or bytes) is a bug, just like writing return '' would be a bug in that function.

  6. ilevkivskyi commented on Apr 27, 2019

    @ilevkivskyi
    MemberAuthor

    (and presumably is more like the real-world case you encountered)

    No, the real world use case was like:

    X = TypeVar('X', One, Two, Three)
    def foo(x: X) -> Tuple[X, str]:
        if x == One('special value'):
            raise ValueError('Do not do foo with special value!')
        return x, bar(x)

    and pragmatically I'd expect that such cases are outnumbered by cases where the comparison if AnyStr to a concrete str (or bytes) is a bug

    So far I didn't find any actual bugs using current semantics, but found some false positives.

  7. JukkaL commented on Apr 29, 2019

    @JukkaL
    Collaborator

    Type variable with value restriction does not seem to be a very commonly used feature (outside stdlib stubs), so even a small number of false positives can indicate a pretty high false positive rate. In particular, Ivan's experiment where this came up targeted a pretty small codebase, I think.

  8. gvanrossum commented on Apr 29, 2019

    @gvanrossum
    Member
  9. self-assigned this
    on Aug 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions