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

Redefinition without reassignment doesn't check existing value #12866

Open
Zeckie opened this issue May 25, 2022 · 3 comments
Open

Redefinition without reassignment doesn't check existing value #12866

Zeckie opened this issue May 25, 2022 · 3 comments
Labels
bug mypy got something wrong topic-variable-scope

Comments

@Zeckie
Copy link

Zeckie commented May 25, 2022

With --allow-redefinition, mypy allows a variable to be redefined, without checking that the existing value is the correct type.

a: str = "foo"
print(a)  # value needs to be used before redefinition
a: int  # but it is really still str
if a > 1:
    ...

https://mypy-play.net/?mypy=latest&python=3.10&flags=allow-redefinition&gist=79d1e9219d66da441050ba730a7c2842

Expected Behaviour

In this example, mypy should detect that a is still a str, and not allow this redefinition.

It could treat the redefinition as though it is a new variable, being assigned the value of the existing one. That would result in an error like:
error: Incompatible types in assignment (expression has type "str", variable has type "int")

Or it could be a new error, like:
error: Redefinition incompatible with existing type (existing type "str", new type "int")

Actual Behaviour

mypy:

Success: no issues found in 1 source file

python:

TypeError: '>' not supported between instances of 'str' and 'int'
@Zeckie Zeckie added the bug mypy got something wrong label May 25, 2022
@DetachHead
Copy link
Contributor

DetachHead commented May 26, 2022

pretty sure this is the same issue as #686

@KotlinIsland
Copy link
Contributor

also #4019/#686

@Zeckie
Copy link
Author

Zeckie commented May 26, 2022

I think this is different enough from those other issues, in that it is not about whether the variable had been assigned before it is redefined.

Rather it is about mypy recognising that when the redefinition statement does not assign a value to the "new" variable (so a statement in the form variable: type rather than one in the form variable: type = expression), the variable's value (and therefore the current type) does not change.

As the redefinition does not change the value, the new type has to be one that includes the (potentially narrowed) existing type of the variable.

Rewriting the original example as though a was 2 separate variables

a_old: str = "foo"
print(a_old)
a_new: int = a_old  # this clearly isn't valid - assigning a string expression to an integer variable
del a_old
if a_new > 1:
    ...

A slightly different case may work at runtime, but I don't think it should be considered valid:

a: int = 1
b = a + 1 # mypy currently does not allow redefinition unless the variable has been used
a: str # I don't consider this to be valid, as a is still an int
a = "foo" # makes this work at runtime
print(a + "bar")

Another example that currently mypy considers to be valid, but I consider to be invalid:

a: object
print(a)
a: int

Though this would be fine:

a: object
assert isinstance(a, int)
a: int

And taking it one step further, mypy currently says this isn't valid, but I think it should be:

def something() -> bool:
    ...

a: object
assert isinstance(a, int)
a: int | str
b = a + 1  # still narrowed to int from the assert (hasn't been reassigned)
if something():
    a="foo"

@Zeckie Zeckie changed the title Redefinition without assignment doesn't check existing value Redefinition without reassignment doesn't check existing value May 26, 2022
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-variable-scope
Projects
None yet
Development

No branches or pull requests

4 participants