False positive when converting union of tuples to union of typed dicts
Bug Report
Mypy fails to preserve types when a union of tuples is transformed to a union of typed dicts. see linked mypy play link
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.11&gist=84a763d09cf7fb68631fa74359d135e7
Expected Behavior
I expect the linked example to pass the type checker
Actual Behavior
Incompatible return value type (got "dict[Literal['a', 'b'], int | str]", expected "A | B") [return-value]
Your Environment
- Mypy version used:
1.4.0 (compiled: yes) - Mypy command-line flags:
--strict - Mypy configuration options from
mypy.ini(and other config files):
[tool.mypy]
strict = true
files = [
"src/",
"tests/",
]
- Python version used:
3.10.1
try to reproduce it in a minimal example that isolates the problematic behavior. This will make it easier for others to understand and potentially provide a solution.
try to reproduce it in a minimal example that isolates the problematic behavior. This will make it easier for others to understand and potentially provide a solution.
the linked gist/playground seems pretty minimal to me. it's a smaller example of real world code I'm trying to type stronger.
This
{
"a": "foo",
"b": "bar",
}
matches dict[Literal['a', 'b'], int | str], but doesn't match A nor B.
Yes, but my code will result in a dict with only one key and one value, and all the types involved make it clear that dict_func must return A or B.
Ahh, I see what's going on!
Given
my_tuple: tuple[Literal['a'], int] | tuple[Literal['b'], str]
...
key, value = my_tuple
I wouldn't expect mypy to keep track of the relation between the two variables key and value after the assignment. That is, it can know "key type is Literal['a', 'b']" but it cannot remember/keep track of the fact that:
keytype isliteral['a']iffvaluetype isintkeytype isliteral['b']iffvaluetype isstr
By unpacking into key, value, you're bound to lose some knowledge.
Now,
my_tuple: tuple[Literal['a'], int] | tuple[Literal['b'], str]
...
return {my_tuple[0]: my_tuple[1]}
this is more debatable, though still obviously harder than figuring out the type of my_tuple[0] independently from my_tuple[1].
By unpacking into
key, value, you're bound to lose some knowledge.
Thank you for spelling it out like that, I can now actually see why this might be an unreasonable ask to mypy/a type checker. I think the problem was that to me as a human, it looks 'obviously type checkable', I can understand why this would be much harder for a program to do.
Should this ticket be closed? (I'd still argue this is a 'bug', but calling this a 'wontfix' also seems reasonable)
Probably? :) You're also welcome to point out any section of the docs that you think we could improve to clarify that.
Closing as per https://github.com/python/mypy/issues/15517#issuecomment-1610229738 We could do a better job of documenting cases where mypy can't reason about relationships between variables, but there are other issues that track this