Skip to content

Better message when inferred variable type conflicts with later use #2529

Closed

Description

@TRManderson

If you can come up with a better name for this issue, please let me know, this one is poor. The naming difficulty also lead to difficulty searching to see if this already existed, so apologies in advance if this is a duplicate issue.

When running this code through the typechecker:

from typing import Union, Dict, List
def g() -> List[Union[str, int]]:
    x = ['a']
    x += [1]
    return x

def f() -> Dict[str, Union[str, int]]:
    d = {'a': 'a'}
    d['b'] = 1
    return d

I get this output:

test.py: note: In function "g":
test.py:4: error: List item 0 has incompatible type "int"
test.py:5: error: Incompatible return value type (got List[str], expected List[Union[str, int]])
test.py: note: In function "f":
test.py:9: error: Incompatible types in assignment (expression has type "int", target has type "str")
test.py:10: error: Incompatible return value type (got Dict[str, str], expected Dict[str, Union[str, int]])

With both these functions, mypy is assuming the type on assignment, then having type errors due to conflicts with the explicitly declared return type.

Surely there should be a way to correctly infer the original type based on the return type?

Activity

  1. JukkaL commented on Dec 7, 2016

    @JukkaL
    Collaborator

    Mypy infers types roughly from top to bottom. This usually makes reasoning about inferred types easier and the implementation is also relatively straightforward. However, there are cases like your example this has undesirable results.

    You can add a type annotation to make the error go away:

    from typing import Union, Dict, List
    def g() -> List[Union[str, int]]:
        x = ['a']  # type: List[Union[str, int]]
        x += [1]
        return x
    
    def f() -> Dict[str, Union[str, int]]:
        d = {'a': 'a'}  # type: Dict[str, Union[str, int]]
        d['b'] = 1
        return d

    Modifying type inference to take the return type into consideration in cases like this would be hard and would complicate the relatively simple and predictable (once you understand a few principles) model that mypy currently uses. However, it might be useful to detect some cases like this and give a better error message. Potential better message:

    test.py: note: In function "g":
    test.py:3: note: Perhaps a type annotation is missing here? Suggestion: List[Union[str, int]]
    test.py:4: error: List item 0 has incompatible type "int"
    test.py:5: error: Incompatible return value type (got List[str], expected List[Union[str, int]])
    
  2. JukkaL commented on Dec 7, 2016

    @JukkaL
    Collaborator

    As it's unlikely that type inference will change for now, I'll update the title to consider a better error message.

  3. changed the title [-]Variable assignment assumes a type that might conflict with later explicit declaration[/-] [+]Better message when inferred variable type conflicts with later use[/+] on Dec 7, 2016
  4. TRManderson commented on Dec 9, 2016

    @TRManderson
    ContributorAuthor

    If #2542 and #2543 get merged I've got a not-so-nice PR to make that includes this kind of error message (without the suggestion, though, I'm still working on that)

  5. quartox commented on May 23, 2017

    @quartox
    Contributor

    I will take a look at this.

  6. quartox commented on May 23, 2017

    @quartox
    Contributor

    Should this note only cover the case when the object type conflicts with the return type or should it also cover the following:

    from typing import List, Any
    def g() -> List[Any]:
        x = ['a']
        x += [1]
        return x
    

    which currently only outputs

    test.py:4: error: List item 0 has incompatible type "int"
    

    I am planning on proceeding with only enhancing the message when it conflicts with the return and not cover the above case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions