Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Closed
Description
problem
comparison chaining has wrong source positions in most contexts
>>>cnd=True>>>a=1if1in2==3else0Traceback (mostrecentcalllast):File"example.py",line43,in<module>a=1if1in2==3else0^^^^^^^^^^^^^^^^^^^^^^^TypeError:argumentof type'int'isnotiterable
This bug requires two things to happen:
- The comparison chain has to contain more than on comparison the type does not matter (
==,in,<=,is,...) - The context has to be something other than an expression
no problem
The following examples work:
only one comparison
Traceback (mostrecentcalllast):File"example.py",line4,in<module>if5<"5":^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'
inside expression
>>>a=Falseor4<"5"<6Traceback (mostrecentcalllast):File"example.py",line15,in<module>a=Falseor4<"5"<6^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'
reason
The problem seems to be the positions in the compiled bytecode:
script:
importdisdeffoo():if1<2<"no int":return1return0forpindis.get_instructions(foo):print(p.positions,p.opname,p.argval)
output (Python 3.11.0rc2+):
Positions(lineno=4,end_lineno=4,col_offset=0,end_col_offset=0)RESUME0Positions(lineno=5,end_lineno=5,col_offset=7,end_col_offset=8)LOAD_CONST1Positions(lineno=5,end_lineno=5,col_offset=9,end_col_offset=10)LOAD_CONST2Positions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)SWAP2Positions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)COPY2Positions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)COMPARE_OP<# range of the whole ifPositions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)POP_JUMP_FORWARD_IF_FALSE30Positions(lineno=5,end_lineno=5,col_offset=11,end_col_offset=19)LOAD_CONSTnointPositions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)COMPARE_OP<# range of the whole ifPositions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)POP_JUMP_FORWARD_IF_FALSE38Positions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)JUMP_FORWARD34Positions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)POP_TOPNonePositions(lineno=5,end_lineno=6,col_offset=4,end_col_offset=16)JUMP_FORWARD38Positions(lineno=6,end_lineno=6,col_offset=15,end_col_offset=16)LOAD_CONST1Positions(lineno=6,end_lineno=6,col_offset=15,end_col_offset=16)RETURN_VALUENonePositions(lineno=7,end_lineno=7,col_offset=11,end_col_offset=12)LOAD_CONST0Positions(lineno=7,end_lineno=7,col_offset=11,end_col_offset=12)RETURN_VALUENone
the generated ast looks fine (snippet):
If( test=Compare( left=Constant( value=1, lineno=5, col_offset=7, # correct end_lineno=5, end_col_offset=8), ops=[ Lt(), Lt()], comparators=[ Constant( value=2, lineno=5, col_offset=9, # correct end_lineno=5, end_col_offset=10), Constant( value='no int', lineno=5, col_offset=11, # correct end_lineno=5, end_col_offset=19)], lineno=5, col_offset=7, end_lineno=5, end_col_offset=19),other examples
here is a list of all the problems I found so far:
>>>if4<"5"<6:...pass...Traceback (mostrecentcalllast):File"example.py",line20,in<module>if4<"5"<6:TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>while4<"5"<6:...pass...Traceback (mostrecentcalllast):File"example.py",line24,in<module>while4<"5"<6:TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>assert4<"5"<6Traceback (mostrecentcalllast):File"example.py",line27,in<module>assert4<"5"<6TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>a=2+(5if4<"5"<6else3)Traceback (mostrecentcalllast):File"example.py",line29,in<module>a=2+(5if4<"5"<6else3)^^^^^^^^^^^^^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>a=[aforain [1]if4<"5"<a ]Traceback (mostrecentcalllast):File"example.py",line34,in<listcomp>a=[aforain [1]if4<"5"<a ]^^^^^^^^^^^^^^^^^^^^^^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>a={aforain [1]if4<"5"<a }Traceback (mostrecentcalllast):File"example.py",line35,in<setcomp>a={aforain [1]if4<"5"<a }^^^^^^^^^^^^^^^^^^^^^^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>a={a:aforain [1]if4<"5"<a }Traceback (mostrecentcalllast):File"example.py",line36,in<dictcomp>a={a:aforain [1]if4<"5"<a }^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>a=list((aforain [1]if4<"5"<a ))Traceback (mostrecentcalllast):File"example.py",line37,in<genexpr>a=list((aforain [1]if4<"5"<a ))^^^^^^^^^^^^^^^^^^^^^^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'>>>cnd=True>>>a=1if1in2==3else0Traceback (mostrecentcalllast):File"example.py",line43,in<module>a=1if1in2==3else0^^^^^^^^^^^^^^^^^^^^^^^TypeError:argumentof type'int'isnotiterable>>>ifTrueand4<"5"<6:...pass...Traceback (mostrecentcalllast):File"example.py",line45,in<module>ifTrueand4<"5"<6:TypeError:'<'notsupportedbetweeninstancesof'int'and'str'
expected result
The positions should always match the ast-node range:
>>>a=list((aforain [1]if4<"5"<a ))Traceback (mostrecentcalllast):File"example.py",line37,in<genexpr>a=list((aforain [1]if4<"5"<a ))^^^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'
or, even better only the failing comparison:
>>>a=list((aforain [1]if4<"5"<a ))Traceback (mostrecentcalllast):File"example.py",line37,in<genexpr>a=list((aforain [1]if4<"5"<a ))^^^^^TypeError:'<'notsupportedbetweeninstancesof'int'and'str'