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

TypeVar bound is ignored in generic alias #10445

Closed
JelleZijlstra opened this issue May 7, 2021 · 5 comments · Fixed by #14159
Closed

TypeVar bound is ignored in generic alias #10445

JelleZijlstra opened this issue May 7, 2021 · 5 comments · Fixed by #14159
Labels
bug mypy got something wrong topic-type-alias TypeAlias and other type alias issues topic-type-variables

Comments

@JelleZijlstra
Copy link
Member

JelleZijlstra commented May 7, 2021

Bug Report

A generic alias using a TypeVar with a bound allows type arguments that don't match the bound

To Reproduce

% cat tvbound.py 
import typing

FooT = typing.TypeVar("FooT", bound=str)
FooIsh = typing.Union[int, FooT]

bat2: FooIsh[float] = 1.0

% mypy tvbound.py
Success: no issues found in 1 source file
% mypy --version
mypy 0.820+dev.e8afde621531880c2b9c51acba8e565a29cde0b1

Expected Behavior

I would expect an error saying that the value of FooT cannot be float.

Found this as a result of microsoft/pyright#1839.

@JelleZijlstra JelleZijlstra added the bug mypy got something wrong label May 7, 2021
@UnquietCode
Copy link

I would like to mention that using mypy 0.91 I see a more general version of this error where the resolved GenericAlias isn't type checked at all regardless of the bound on the TypeVar. That is:

FooT = typing.TypeVar("FooT")
FooIsh = typing.Union[int, FooT]

bat2: FooIsh[float] = "passes"

fails to report an error.

@AlexWaygood
Copy link
Member

I just closed #13086 as a duplicate of this issue, but @harahu notes in that issue that this bug is also present for generic type aliases that use constrained TypeVars (as well as those that use bound TypeVars):

from typing import Generic, TypeVar, TypeAlias

U = TypeVar("U", bytes, str)
RestrictedTuple: TypeAlias = tuple[U]
i_am_illegal: RestrictedTuple[int]  # Passes, even though this type shouldn't be possible!

ilevkivskyi added a commit that referenced this issue Nov 24, 2022
Fixes #11855 
Fixes #7084
Fixes #10445
Should fix #4987

After thinking about this for some time, it looks like the best way to
implement this is by switching type aliases from unbound to bound type
variables. Then I can essentially simply share (or copy in one small
place, to avoid cyclic imports) all the logic that currently exists for
`ParamSpec` and `Concatenate` in `expand_type()` etc.

This will also address a big piece of tech debt, and will get some
benefits (almost) for free, such as checking bounds/values for alias
type variables, and much tighter handling of unbound type variables.

Note that in this PR I change logic for emitting some errors, I try to
avoid showing multiple errors for the same location/reason. But this is
not an essential part of this PR (it is just some test cases would
otherwise fail with even more error messages), I can reconsider if there
are objections.
@harahu
Copy link

harahu commented Nov 24, 2022

@ilevkivskyi Are you sure this should be closed? I just made a minimal playground example out of the issue I pointed out in #13086, that @AlexWaygood mentioned above:

https://mypy-play.net/?mypy=master&python=3.11&flags=strict&gist=b251ba96b0e4c9632c8ba162f81280e8

This example still fails when run with mypy from the master branch.

@AlexWaygood
Copy link
Member

AlexWaygood commented Nov 24, 2022

@harahu, if I run mypy with the master branch checked out locally on this snippet:

import typing

FooT = typing.TypeVar("FooT", bound=str)
FooIsh = typing.Union[int, FooT]
bat: FooIsh[float] = 1.0

FooT2 = typing.TypeVar("FooT2")
FooIsh2 = typing.Union[int, FooT]
bat2: FooIsh[float] = "fails"

U = typing.TypeVar("U", bytes, str)
RestrictedTuple: typing.TypeAlias = tuple[U]
i_am_illegal: RestrictedTuple[int]

Then this is the output:

test.py:5: error: Type argument "float" of "FooIsh" must be a subtype of "str"  [type-var]
test.py:9: error: Incompatible types in assignment (expression has type "str", variable has type "Union[int, float]")  [assignment]
test.py:13: error: Value of type variable "U" of "RestrictedTuple" cannot be "int"  [type-var]
Found 3 errors in 1 file (checked 1 source file)

This seems like the correct output to me; I think it was correct for this issue to be closed.

The "run mypy with the master branch" option on mypy playground is often quite out of sync with what mypy's actual master branch is, unfortunately. (I sort-of think having that option is not particularly helpful if it's not going to be automatically synced with mypy's latest commit). Note that mypy playground isn't run by mypy; it's a third-party project that you can report issues to here: https://github.com/ymyzk/mypy-playground.

@harahu
Copy link

harahu commented Nov 24, 2022

I see. You correctly pointed out where I was mistaken. I assumed playground was up to date. Sorry about the confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-type-alias TypeAlias and other type alias issues topic-type-variables
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants