Skip to content

Base {} Dict Should Infer from Function Return Type #18700

Open

Description

@dibrinsofor

Bug Report

I think this may be a possible refinement bug. Mypy flags an error on the assignment line, and not the return statement. So it is clear Mypy flags {} as a subtype of {str, str}, but I think this should be one of those cases where having refinements should reduce the annotation burden on developers. Unless we want to throw an error because of imprecision.

To Reproduce

# Ideally, a small sample program that demonstrates the problem.
# Or even better, a reproducible playground link https://mypy-play.net/ (use the "Gist" button)
def func() -> dict[str, str]: 
    x = {} ## error here for annot 
    return x

reproducible link: Gist Playground

Expected Behavior

I would expect Mypy to notice the reveal_type(x) as dict[str, str] based off the functions return type and not raise an error.

Actual Behavior

main.py:2: error: Need type annotation for "x" (hint: "x: dict[<type>, <type>] = ...")  [var-annotated]

Your Environment

  • Mypy version used:
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used:

Activity

  1. Bellkross commented on Feb 18, 2025

    @Bellkross

    Hey, is it OK if I contribute to solving this one? Never contributed to open-source before, but I like mypy and would like to try.

  2. A5rocks commented on Feb 19, 2025

    @A5rocks
    Collaborator

    Sure but I suspect an issue labelled good first issue would be better.

    Edit: oops, they're all taken. Looking through recent issues, I would suspect #18692 is an easier fix than this (though I'm not familiar enough with mypy to know for sure without... doing it myself).

  3. Bellkross commented on Feb 19, 2025

    @Bellkross

    Sure but I suspect an issue labelled good first issue would be better.

    Thank you, I will try to fix this one then. I will find something easier if I make no progress in a couple of weeks.

    Edit: oops, they're all taken. Looking through recent issues, I would suspect #18692 is an easier fix than this (though I'm not familiar enough with mypy to know for sure without... doing it myself).

    Yeah, since all “good first issue”s are taken I decided to try this one. And I like the issue because I experienced it myself.

  4. dibrinsofor commented on Feb 19, 2025

    @dibrinsofor
    Author

    I think I can take this one up this weekend. Happy to pair with @Bellkross

  5. Bellkross commented on Feb 20, 2025

    @Bellkross

    I think I can take this one up this weekend. Happy to pair with @Bellkross

    Would be happy to pair up @dibrinsofor

  6. Bellkross commented on Feb 21, 2025

    @Bellkross

    @dibrinsofor , I will not be working on this issue, feel free to do it without me, fyi.

    Something came up and my plans for nearest several weeks have changed

  7. Bellkross commented on Feb 27, 2025

    @Bellkross

    @dibrinsofor hey, I am back and can work on the issue now. We can get in contact this weekend if you want to.
    I have started to look into the issue, getting familiar with the code

  8. dibrinsofor commented on Feb 27, 2025

    @dibrinsofor
    Author

    @Bellkross sounds good. I can shoot you an email and we can arrange on a time.

  9. Bellkross commented on Mar 1, 2025

    @Bellkross

    I just realized that I would rather work on an issue alone, so will let @dibrinsofor solve this one since they are the author. Apologies for confusion. Will be looking for something else.

  10. dibrinsofor commented on Mar 2, 2025

    @dibrinsofor
    Author

    I was thinking about this today, and I'm not sure we should modify how propagation (or elaboration?) works here, maybe just introduce a special case to avoid raising errors in situations like this, but even then, it does not seem very beneficial.

    For one, there's no control flow to trigger narrowing, and even if there were, I don’t see how propagating the refined type back to the initial definition would be beneficial.

    But i did notice some nits while probing this.

    x = ()
    reveal_type(x) # Tuple[()]
    
    def funcSet() -> tuple[str]: 
        x = tuple() # E: 
        reveal_type(x)
        return x
    

    This raises this error without a hint, error: Need type annotation for "x", whereas the same sample with a set or dict raises this error: Need type annotation for "x" (hint: "x: Set[<type>] = ...")

    I just need some go ahead, and I will pivot to addressing the nits instead.

  11. A5rocks commented on Mar 2, 2025

    @A5rocks
    Collaborator

    An empty tuple can be annotated as having no contents so it doesn't need an annotation. (I'm surprised calling tuple() doesn't do that, but I suppose that's lower priority)

    I would recommend looking at how currently mypy handles inferring types given:

    x = []
    x.append(5)

    and extend that to a return statement. Like I said previously though, I'm not sure this is very easy.

  12. wyattscarpenter commented on May 16, 2025

    @wyattscarpenter
    Contributor

    @dibrinsofor I think your original idea of propagating the type backwards from the return statement of a type with a known return signature is good 🙂. It would be more elegant than introducing a special case to suppress with error message, and could conceivably help with some other situations. (However, if you don't think it's not that beneficial, feel free to close the issue; don't keep it open on my account.)

    Mypy flags an error on the assignment line, and not the return statement. So it is clear Mypy flags {} as a subtype of {str, str}

    I get Revealed type is "builtins.dict[Any, Any]", which is not really a subtype, and so this train of thought seems misleading to me (in case anyone is starting to investigate it from reading this comment and needs a tip). Close enough, though.

    I agree with @A5rocks about the nit. It's not surprising that () doesn't need an annotation, and I am kind of surprised that tuple() doesn't have a type of tuple[()] as well (its type is... builtins.tuple[Never, ...]? Any number of elements, none of which can exist? Weird.)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-inferenceWhen to infer types or require explicit annotations

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions