You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Binder loses narrowed type of a variable if variable may be uninitialized #18619
Mypy sometimes loses track of the narrowed type of a variable, at least when the variable can be uninitialized in some code paths. This can happen when variables is both initialized and narrowed in a conditional block.
To Reproduce
ifint():
x: int|strx=0x=str(x)
reveal_type(x) # int | str
This issue interferes with inferring union types from assignments (#18568).
@ilevkivskyi Do you have an idea of how to fix this, since you did some work on the binder recently? If a variable hasn't been assigned in some conditional code path, maybe the type should be treated as Never when merging types from different code paths?
First of all I am far from binder expert :-), but unfortunately I don't think there is an easy/clean fix for this. The problem is that the textually first assignment is the one that sets the declared type. So these two are identical from the point of view of the binder
ifcond():
x: int|str= ...
x=0
and
x: int|str= ...
ifcond():
x=0
while for the second one we obviously want to keep the type as union. We would need to track somehow where the variable was first declared and act accordingly. I however don't have any simple/clear idea on this.
The only relatively clean solution I see is we would need to track in which frames a variable is readable, and ignore frames without information when popping them if a variable is not readable in that frame (now if there is at least one frame without information, we erase all information so far, see update_from_options()). But IIUC this will essentially duplicate the work done in PossiblyUndefinedVariableVisitor.
The only relatively clean solution I see is we would need to track in which frames a variable is readable, and ignore frames without information when popping them if a variable is not readable in that frame
This looks promising. In my prototype implementation I now update binder on initial assignment, so that if there is nothing in binder, the variable is uninitialized in that frame. This broke a bunch of things, however, but I hope I can fix all the resulting issues. This will possibly be enabled only when the new type inference logic is enabled (inferring unions from assignments) to reduce potential for backward compatibility breaks.
Activity
ilevkivskyi commentedon Feb 6, 2025
First of all I am far from binder expert :-), but unfortunately I don't think there is an easy/clean fix for this. The problem is that the textually first assignment is the one that sets the declared type. So these two are identical from the point of view of the binder
and
while for the second one we obviously want to keep the type as union. We would need to track somehow where the variable was first declared and act accordingly. I however don't have any simple/clear idea on this.
ilevkivskyi commentedon Feb 6, 2025
The only relatively clean solution I see is we would need to track in which frames a variable is readable, and ignore frames without information when popping them if a variable is not readable in that frame (now if there is at least one frame without information, we erase all information so far, see
update_from_options()). But IIUC this will essentially duplicate the work done inPossiblyUndefinedVariableVisitor.JukkaL commentedon Feb 7, 2025
This looks promising. In my prototype implementation I now update binder on initial assignment, so that if there is nothing in binder, the variable is uninitialized in that frame. This broke a bunch of things, however, but I hope I can fix all the resulting issues. This will possibly be enabled only when the new type inference logic is enabled (inferring unions from assignments) to reduce potential for backward compatibility breaks.
Saunakghosh10 commentedon Feb 11, 2025
trying to fix this
JukkaL commentedon Feb 11, 2025
@Saunakghosh10 I'm working on this and have a prototype implementation.
Add flag to allow more flexible variable redefinition (python#18727)