@@ -396,6 +396,11 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
396396
397397 jump_multiplier = 2
398398
399+ # Python 3.14+ push nulls are used to signal kwargs for CALL_FUNCTION_EX
400+ # so there must be a little extra bookkeeping even if we don't care about
401+ # the nulls themselves.
402+ last_op_push_null = 0
403+
399404 last_pc = - 1
400405 last_real_opname = opname = None
401406 while pc < end : # pylint: disable=too-many-nested-blocks
@@ -441,7 +446,8 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
441446 elif op in dis .haslocal :
442447 # Args to double-fast opcodes are bit manipulated, correct the arg
443448 # for printing + avoid the out-of-index
444- if dis .opname [op ] == 'LOAD_FAST_LOAD_FAST' :
449+ if dis .opname [op ] == 'LOAD_FAST_LOAD_FAST' or dis .opname [
450+ op ] == "LOAD_FAST_BORROW_LOAD_FAST_BORROW" :
445451 print (
446452 '(' + co .co_varnames [arg >> 4 ] + ', ' +
447453 co .co_varnames [arg & 15 ] + ')' ,
@@ -450,6 +456,8 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
450456 print ('(' + co .co_varnames [arg & 15 ] + ')' , end = ' ' )
451457 elif dis .opname [op ] == 'STORE_FAST_STORE_FAST' :
452458 pass
459+ elif dis .opname [op ] == 'LOAD_DEREF' :
460+ pass
453461 else :
454462 print ('(' + co .co_varnames [arg ] + ')' , end = ' ' )
455463 elif op in dis .hascompare :
@@ -512,6 +520,12 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
512520 # stack[-has_kwargs]: Map of keyword args.
513521 # stack[-1 - has_kwargs]: Iterable of positional args.
514522 # stack[-2 - has_kwargs]: Function to call.
523+ if arg is None :
524+ # CALL_FUNCTION_EX does not take an arg in 3.14, instead the
525+ # signaling for kwargs is done via a PUSH_NULL instruction
526+ # right before CALL_FUNCTION_EX. A PUSH_NULL indicates that
527+ # there are no kwargs.
528+ arg = ~ last_op_push_null
515529 has_kwargs : int = arg & 1
516530 pop_count = has_kwargs + 2
517531 if has_kwargs :
@@ -680,6 +694,9 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
680694 jmp_state = state .copy ()
681695 jmp_state .stack .pop ()
682696 state .stack .append (element_type (state .stack [- 1 ]))
697+ elif opname == 'POP_ITER' :
698+ # Introduced in 3.14.
699+ state .stack .pop ()
683700 elif opname == 'COPY_FREE_VARS' :
684701 # Helps with calling closures, but since we aren't executing
685702 # them we can treat this as a no-op
@@ -694,6 +711,10 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
694711 # We're treating this as a no-op to avoid having to check
695712 # for extra None values on the stack when we extract return
696713 # values
714+ last_op_push_null = 1
715+ pass
716+ elif opname == 'NOT_TAKEN' :
717+ # NOT_TAKEN is a no-op introduced in 3.14.
697718 pass
698719 elif opname == 'PRECALL' :
699720 # PRECALL is a no-op.
@@ -727,6 +748,10 @@ def infer_return_type_func(f, input_types, debug=False, depth=0):
727748 else :
728749 raise TypeInferenceError ('unable to handle %s' % opname )
729750
751+ # Clear check for previous push_null.
752+ if opname != 'PUSH_NULL' and last_op_push_null == 1 :
753+ last_op_push_null = 0
754+
730755 if jmp is not None :
731756 # TODO(robertwb): Is this guaranteed to converge?
732757 new_state = states [jmp ] | jmp_state
0 commit comments