Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False negative after isinstance check #5811

Closed
TV4Fun opened this issue Oct 19, 2018 · 1 comment
Closed

False negative after isinstance check #5811

TV4Fun opened this issue Oct 19, 2018 · 1 comment

Comments

@TV4Fun
Copy link
Contributor

TV4Fun commented Oct 19, 2018

Consider the following code:

class A: ...
class B: ...
class C(A, B): ...

def f(a: A) -> B: ...


def g(b: B) -> None:
    if isinstance(b, A):
        reveal_type(b)
        b = f(B())

g(C())

It seems that mypy assumes that is is impossible for the isinstance check to be true and does not evaluate what follows it. This code produces no errors. Even the reveal_type here is ignored. At the very least, the type checker should be aware of the existence of the class C, which inherits from both A and B, but that seems like it has a high potential for error. Better would just be to assume that it is possible for something to be an instance of both A and B, as someone could also create such a class in a separate file that imports this file, unless the type checker has a way to be sure the two types are mutually exclusive.

@ilevkivskyi had suggested in the similar issue #5423, that in strict mode, mypy should still type check unreachable code, but I would suggest, in addition to that, adding a warning for any code that mypy thinks is unreachable. Doing that might have allowed us to catch this example, which I found in mypy/server/astdiff.py: 165:

def snapshot_definition(node: Optional[SymbolNode],
                        common: Tuple[object, ...]) -> Tuple[object, ...]:
    """Create a snapshot description of a symbol table node.

    The representation is nested tuples and dicts. Only externally
    visible attributes are included.
    """
    if isinstance(node, FuncBase):
        # TODO: info
        if node.type:
            signature = snapshot_type(node.type)
        else:
            signature = snapshot_untyped_signature(node)

Note that snapshot_untyped_signature expects a Union[OverloadedFuncDef, FuncItem], and while it is true that OverloadedFuncDef and FuncItem are the only things that directly inherit from FuncBase, and FuncBase itself is abstract, I don't think the type checker is smart enough to know that, nor should it be. The issue here is that node is an Optional[SymbolNode], and while OverloadedFuncDef inherits from SymbolNode, FuncBase itself does not, so really we are expecting either an OverloadedFuncDef or a FuncDef here, but the type checker has no way of knowing that. PyCharm did give me a warning about this, and this created some problems when I was attempting to refactor some code in this function, which was using a slightly different check that mypy could not determine was unreachable, and so caused a type error where there wasn't one before, which was very confusing to me for a little while.

@TV4Fun
Copy link
Contributor Author

TV4Fun commented Oct 20, 2018

I see this has already been discussed extensively, so closing as a duplicate of #3603, but may want to do something about the typing in astdiff.py.

@TV4Fun TV4Fun closed this as completed Oct 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant