numba-cuda 0.21.1__cp313-cp313-win_amd64.whl → 0.24.0__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. numba_cuda/VERSION +1 -1
  2. numba_cuda/numba/cuda/__init__.py +4 -1
  3. numba_cuda/numba/cuda/_compat.py +47 -0
  4. numba_cuda/numba/cuda/api.py +4 -1
  5. numba_cuda/numba/cuda/cext/_dispatcher.cp313-win_amd64.pyd +0 -0
  6. numba_cuda/numba/cuda/cext/_dispatcher.cpp +8 -40
  7. numba_cuda/numba/cuda/cext/_hashtable.cpp +5 -0
  8. numba_cuda/numba/cuda/cext/_helperlib.cp313-win_amd64.pyd +0 -0
  9. numba_cuda/numba/cuda/cext/_pymodule.h +1 -1
  10. numba_cuda/numba/cuda/cext/_typeconv.cp313-win_amd64.pyd +0 -0
  11. numba_cuda/numba/cuda/cext/_typeof.cpp +56 -119
  12. numba_cuda/numba/cuda/cext/mviewbuf.c +7 -1
  13. numba_cuda/numba/cuda/cext/mviewbuf.cp313-win_amd64.pyd +0 -0
  14. numba_cuda/numba/cuda/cloudpickle/cloudpickle.py +4 -5
  15. numba_cuda/numba/cuda/codegen.py +46 -12
  16. numba_cuda/numba/cuda/compiler.py +15 -9
  17. numba_cuda/numba/cuda/core/analysis.py +29 -21
  18. numba_cuda/numba/cuda/core/annotations/pretty_annotate.py +1 -1
  19. numba_cuda/numba/cuda/core/annotations/type_annotations.py +4 -4
  20. numba_cuda/numba/cuda/core/base.py +12 -11
  21. numba_cuda/numba/cuda/core/bytecode.py +21 -13
  22. numba_cuda/numba/cuda/core/byteflow.py +336 -90
  23. numba_cuda/numba/cuda/core/compiler.py +3 -4
  24. numba_cuda/numba/cuda/core/compiler_machinery.py +3 -3
  25. numba_cuda/numba/cuda/core/config.py +5 -7
  26. numba_cuda/numba/cuda/core/consts.py +1 -1
  27. numba_cuda/numba/cuda/core/controlflow.py +17 -9
  28. numba_cuda/numba/cuda/core/cuda_errors.py +917 -0
  29. numba_cuda/numba/cuda/core/errors.py +4 -912
  30. numba_cuda/numba/cuda/core/inline_closurecall.py +82 -67
  31. numba_cuda/numba/cuda/core/interpreter.py +334 -160
  32. numba_cuda/numba/cuda/core/ir.py +191 -119
  33. numba_cuda/numba/cuda/core/ir_utils.py +149 -128
  34. numba_cuda/numba/cuda/core/postproc.py +8 -8
  35. numba_cuda/numba/cuda/core/pythonapi.py +3 -0
  36. numba_cuda/numba/cuda/core/rewrites/ir_print.py +6 -3
  37. numba_cuda/numba/cuda/core/rewrites/static_binop.py +1 -1
  38. numba_cuda/numba/cuda/core/rewrites/static_getitem.py +5 -5
  39. numba_cuda/numba/cuda/core/rewrites/static_raise.py +3 -3
  40. numba_cuda/numba/cuda/core/ssa.py +5 -5
  41. numba_cuda/numba/cuda/core/transforms.py +29 -16
  42. numba_cuda/numba/cuda/core/typed_passes.py +10 -10
  43. numba_cuda/numba/cuda/core/typeinfer.py +42 -27
  44. numba_cuda/numba/cuda/core/untyped_passes.py +82 -65
  45. numba_cuda/numba/cuda/cpython/unicode.py +2 -2
  46. numba_cuda/numba/cuda/cpython/unicode_support.py +1 -3
  47. numba_cuda/numba/cuda/cudadecl.py +0 -13
  48. numba_cuda/numba/cuda/cudadrv/devicearray.py +10 -9
  49. numba_cuda/numba/cuda/cudadrv/driver.py +142 -519
  50. numba_cuda/numba/cuda/cudadrv/dummyarray.py +4 -0
  51. numba_cuda/numba/cuda/cudadrv/nvrtc.py +87 -32
  52. numba_cuda/numba/cuda/cudaimpl.py +0 -12
  53. numba_cuda/numba/cuda/debuginfo.py +25 -0
  54. numba_cuda/numba/cuda/descriptor.py +1 -1
  55. numba_cuda/numba/cuda/device_init.py +4 -7
  56. numba_cuda/numba/cuda/deviceufunc.py +3 -6
  57. numba_cuda/numba/cuda/dispatcher.py +39 -49
  58. numba_cuda/numba/cuda/intrinsics.py +150 -1
  59. numba_cuda/numba/cuda/libdeviceimpl.py +1 -2
  60. numba_cuda/numba/cuda/lowering.py +36 -29
  61. numba_cuda/numba/cuda/memory_management/nrt.py +10 -14
  62. numba_cuda/numba/cuda/np/arrayobj.py +61 -9
  63. numba_cuda/numba/cuda/np/numpy_support.py +32 -9
  64. numba_cuda/numba/cuda/np/polynomial/polynomial_functions.py +4 -3
  65. numba_cuda/numba/cuda/printimpl.py +20 -0
  66. numba_cuda/numba/cuda/serialize.py +10 -0
  67. numba_cuda/numba/cuda/stubs.py +0 -11
  68. numba_cuda/numba/cuda/testing.py +4 -8
  69. numba_cuda/numba/cuda/tests/benchmarks/test_kernel_launch.py +21 -4
  70. numba_cuda/numba/cuda/tests/cudadrv/test_context_stack.py +1 -2
  71. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_driver.py +195 -51
  72. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_memory.py +6 -2
  73. numba_cuda/numba/cuda/tests/cudadrv/test_emm_plugins.py +3 -1
  74. numba_cuda/numba/cuda/tests/cudadrv/test_events.py +1 -1
  75. numba_cuda/numba/cuda/tests/cudadrv/test_linker.py +6 -7
  76. numba_cuda/numba/cuda/tests/cudadrv/test_module_callbacks.py +11 -12
  77. numba_cuda/numba/cuda/tests/cudadrv/test_nvjitlink.py +53 -23
  78. numba_cuda/numba/cuda/tests/cudapy/test_analysis.py +61 -9
  79. numba_cuda/numba/cuda/tests/cudapy/test_atomics.py +6 -0
  80. numba_cuda/numba/cuda/tests/cudapy/test_caching.py +47 -0
  81. numba_cuda/numba/cuda/tests/cudapy/test_compiler.py +22 -1
  82. numba_cuda/numba/cuda/tests/cudapy/test_complex.py +13 -0
  83. numba_cuda/numba/cuda/tests/cudapy/test_copy_propagate.py +1 -1
  84. numba_cuda/numba/cuda/tests/cudapy/test_debug.py +1 -1
  85. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo.py +94 -0
  86. numba_cuda/numba/cuda/tests/cudapy/test_device_array_capture.py +243 -0
  87. numba_cuda/numba/cuda/tests/cudapy/test_dispatcher.py +3 -3
  88. numba_cuda/numba/cuda/tests/cudapy/test_extending.py +1 -1
  89. numba_cuda/numba/cuda/tests/cudapy/test_numba_interop.py +35 -0
  90. numba_cuda/numba/cuda/tests/cudapy/test_print.py +51 -0
  91. numba_cuda/numba/cuda/tests/cudapy/test_vector_type.py +37 -35
  92. numba_cuda/numba/cuda/tests/cudapy/test_warp_ops.py +117 -1
  93. numba_cuda/numba/cuda/tests/doc_examples/test_globals.py +111 -0
  94. numba_cuda/numba/cuda/tests/nocuda/test_dummyarray.py +61 -0
  95. numba_cuda/numba/cuda/tests/nrt/test_nrt.py +31 -0
  96. numba_cuda/numba/cuda/tests/support.py +11 -0
  97. numba_cuda/numba/cuda/types/cuda_functions.py +1 -1
  98. numba_cuda/numba/cuda/typing/asnumbatype.py +37 -2
  99. numba_cuda/numba/cuda/typing/context.py +3 -1
  100. numba_cuda/numba/cuda/typing/typeof.py +51 -2
  101. {numba_cuda-0.21.1.dist-info → numba_cuda-0.24.0.dist-info}/METADATA +4 -13
  102. {numba_cuda-0.21.1.dist-info → numba_cuda-0.24.0.dist-info}/RECORD +106 -105
  103. numba_cuda/numba/cuda/cext/_devicearray.cp313-win_amd64.pyd +0 -0
  104. numba_cuda/numba/cuda/cext/_devicearray.cpp +0 -159
  105. numba_cuda/numba/cuda/cext/_devicearray.h +0 -29
  106. numba_cuda/numba/cuda/intrinsic_wrapper.py +0 -41
  107. {numba_cuda-0.21.1.dist-info → numba_cuda-0.24.0.dist-info}/WHEEL +0 -0
  108. {numba_cuda-0.21.1.dist-info → numba_cuda-0.24.0.dist-info}/licenses/LICENSE +0 -0
  109. {numba_cuda-0.21.1.dist-info → numba_cuda-0.24.0.dist-info}/licenses/LICENSE.numba +0 -0
  110. {numba_cuda-0.21.1.dist-info → numba_cuda-0.24.0.dist-info}/top_level.txt +0 -0
@@ -27,7 +27,7 @@ from numba.cuda.core.unsafe import eh
27
27
  from numba.cuda.cpython.unsafe.tuple import unpack_single_tuple
28
28
 
29
29
 
30
- if PYVERSION in ((3, 12), (3, 13)):
30
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
31
31
  # Operands for CALL_INTRINSIC_1
32
32
  from numba.cuda.core.byteflow import CALL_INTRINSIC_1_Operand as ci1op
33
33
  elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
@@ -217,8 +217,8 @@ def _call_function_ex_replace_kws_large(
217
217
  # The first value must be a constant.
218
218
  const_stmt = old_body[search_start]
219
219
  if not (
220
- isinstance(const_stmt, ir.Assign)
221
- and isinstance(const_stmt.value, ir.Const)
220
+ isinstance(const_stmt, ir.assign_types)
221
+ and isinstance(const_stmt.value, ir.const_types)
222
222
  ):
223
223
  # We cannot handle this format so raise the
224
224
  # original error message.
@@ -231,8 +231,8 @@ def _call_function_ex_replace_kws_large(
231
231
  while search_start <= search_end and not found_getattr:
232
232
  getattr_stmt = old_body[search_start]
233
233
  if (
234
- isinstance(getattr_stmt, ir.Assign)
235
- and isinstance(getattr_stmt.value, ir.Expr)
234
+ isinstance(getattr_stmt, ir.assign_types)
235
+ and isinstance(getattr_stmt.value, ir.expr_types)
236
236
  and getattr_stmt.value.op == "getattr"
237
237
  and (getattr_stmt.value.value.name == buildmap_name)
238
238
  and getattr_stmt.value.attr == "__setitem__"
@@ -262,8 +262,8 @@ def _call_function_ex_replace_kws_large(
262
262
  raise UnsupportedBytecodeError(errmsg)
263
263
  setitem_stmt = old_body[search_start + 1]
264
264
  if not (
265
- isinstance(setitem_stmt, ir.Assign)
266
- and isinstance(setitem_stmt.value, ir.Expr)
265
+ isinstance(setitem_stmt, ir.assign_types)
266
+ and isinstance(setitem_stmt.value, ir.expr_types)
267
267
  and setitem_stmt.value.op == "call"
268
268
  and (setitem_stmt.value.func.name == getattr_stmt.target.name)
269
269
  and len(setitem_stmt.value.args) == 2
@@ -366,8 +366,8 @@ def _call_function_ex_replace_args_large(
366
366
  # tuple.
367
367
  search_start = 0
368
368
  total_args = []
369
- if isinstance(vararg_stmt, ir.Assign) and isinstance(
370
- vararg_stmt.value, ir.Var
369
+ if isinstance(vararg_stmt, ir.assign_types) and isinstance(
370
+ vararg_stmt.value, ir.var_types
371
371
  ):
372
372
  target_name = vararg_stmt.value.name
373
373
  # If there is an initial assignment, delete it
@@ -387,9 +387,9 @@ def _call_function_ex_replace_args_large(
387
387
  while search_end >= search_start:
388
388
  concat_stmt = old_body[search_end]
389
389
  if (
390
- isinstance(concat_stmt, ir.Assign)
390
+ isinstance(concat_stmt, ir.assign_types)
391
391
  and concat_stmt.target.name == target_name
392
- and isinstance(concat_stmt.value, ir.Expr)
392
+ and isinstance(concat_stmt.value, ir.expr_types)
393
393
  and concat_stmt.value.op == "build_tuple"
394
394
  and not concat_stmt.value.items
395
395
  ):
@@ -404,9 +404,9 @@ def _call_function_ex_replace_args_large(
404
404
  # We expect to find another arg to append.
405
405
  # The first stmt must be a binop "add"
406
406
  if (search_end == search_start) or not (
407
- isinstance(concat_stmt, ir.Assign)
407
+ isinstance(concat_stmt, ir.assign_types)
408
408
  and (concat_stmt.target.name == target_name)
409
- and isinstance(concat_stmt.value, ir.Expr)
409
+ and isinstance(concat_stmt.value, ir.expr_types)
410
410
  and concat_stmt.value.op == "binop"
411
411
  and concat_stmt.value.fn == operator.add
412
412
  ):
@@ -418,8 +418,8 @@ def _call_function_ex_replace_args_large(
418
418
  # build_tuple containing the arg.
419
419
  arg_tuple_stmt = old_body[search_end - 1]
420
420
  if not (
421
- isinstance(arg_tuple_stmt, ir.Assign)
422
- and isinstance(arg_tuple_stmt.value, ir.Expr)
421
+ isinstance(arg_tuple_stmt, ir.assign_types)
422
+ and isinstance(arg_tuple_stmt.value, ir.expr_types)
423
423
  and (arg_tuple_stmt.value.op == "build_tuple")
424
424
  and len(arg_tuple_stmt.value.items) == 1
425
425
  ):
@@ -448,7 +448,7 @@ def _call_function_ex_replace_args_large(
448
448
  keep_looking = True
449
449
  while search_end >= search_start and keep_looking:
450
450
  next_stmt = old_body[search_end]
451
- if isinstance(next_stmt, ir.Assign) and (
451
+ if isinstance(next_stmt, ir.assign_types) and (
452
452
  next_stmt.target.name == target_name
453
453
  ):
454
454
  keep_looking = False
@@ -522,8 +522,8 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
522
522
  new_body = []
523
523
  for i, stmt in enumerate(blk.body):
524
524
  if (
525
- isinstance(stmt, ir.Assign)
526
- and isinstance(stmt.value, ir.Expr)
525
+ isinstance(stmt, ir.assign_types)
526
+ and isinstance(stmt.value, ir.expr_types)
527
527
  and stmt.value.op == "call"
528
528
  and stmt.value.varkwarg is not None
529
529
  ):
@@ -548,7 +548,7 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
548
548
  while varkwarg_loc >= 0 and not found:
549
549
  keyword_def = blk.body[varkwarg_loc]
550
550
  if (
551
- isinstance(keyword_def, ir.Assign)
551
+ isinstance(keyword_def, ir.assign_types)
552
552
  and keyword_def.target.name == varkwarg.name
553
553
  ):
554
554
  found = True
@@ -558,7 +558,7 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
558
558
  kws
559
559
  or not found
560
560
  or not (
561
- isinstance(keyword_def.value, ir.Expr)
561
+ isinstance(keyword_def.value, ir.expr_types)
562
562
  and keyword_def.value.op == "build_map"
563
563
  )
564
564
  ):
@@ -624,7 +624,7 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
624
624
  while vararg_loc >= 0 and not found:
625
625
  args_def = blk.body[vararg_loc]
626
626
  if (
627
- isinstance(args_def, ir.Assign)
627
+ isinstance(args_def, ir.assign_types)
628
628
  and args_def.target.name == vararg.name
629
629
  ):
630
630
  found = True
@@ -635,7 +635,7 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
635
635
  # then we can't handle this format.
636
636
  raise UnsupportedBytecodeError(errmsg)
637
637
  if (
638
- isinstance(args_def.value, ir.Expr)
638
+ isinstance(args_def.value, ir.expr_types)
639
639
  and args_def.value.op == "build_tuple"
640
640
  ):
641
641
  # n_args <= 30 case.
@@ -656,7 +656,7 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
656
656
  already_deleted_defs,
657
657
  )
658
658
  elif (
659
- isinstance(args_def.value, ir.Expr)
659
+ isinstance(args_def.value, ir.expr_types)
660
660
  and args_def.value.op == "list_to_tuple"
661
661
  ):
662
662
  # If there is a call with vararg we need to check
@@ -708,8 +708,8 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
708
708
  # Update the definition
709
709
  func_ir._definitions[stmt.target.name].append(new_call)
710
710
  elif (
711
- isinstance(stmt, ir.Assign)
712
- and isinstance(stmt.value, ir.Expr)
711
+ isinstance(stmt, ir.assign_types)
712
+ and isinstance(stmt.value, ir.expr_types)
713
713
  and stmt.value.op == "call"
714
714
  and stmt.value.vararg is not None
715
715
  ):
@@ -725,7 +725,10 @@ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
725
725
  # If this value is still a list to tuple raise the
726
726
  # exception.
727
727
  expr = func_ir._definitions[vararg_name][0]
728
- if isinstance(expr, ir.Expr) and expr.op == "list_to_tuple":
728
+ if (
729
+ isinstance(expr, ir.expr_types)
730
+ and expr.op == "list_to_tuple"
731
+ ):
729
732
  raise UnsupportedBytecodeError(errmsg)
730
733
 
731
734
  new_body.append(stmt)
@@ -771,7 +774,7 @@ def peep_hole_list_to_tuple(func_ir):
771
774
  _DEBUG = False
772
775
 
773
776
  # For all blocks
774
- for offset, blk in func_ir.blocks.items():
777
+ for blk in func_ir.blocks.values():
775
778
  # keep doing the peephole rewrite until nothing is left that matches
776
779
  while True:
777
780
  # first try and find a matching region
@@ -780,17 +783,17 @@ def peep_hole_list_to_tuple(func_ir):
780
783
  found = False
781
784
  for idx in reversed(range(len(blk.body))):
782
785
  stmt = blk.body[idx]
783
- if isinstance(stmt, ir.Assign):
786
+ if isinstance(stmt, ir.assign_types):
784
787
  value = stmt.value
785
788
  if (
786
- isinstance(value, ir.Expr)
789
+ isinstance(value, ir.expr_types)
787
790
  and value.op == "list_to_tuple"
788
791
  ):
789
792
  target_list = value.info[0]
790
793
  found = True
791
794
  bt = (idx, stmt)
792
795
  if found:
793
- if isinstance(stmt, ir.Assign):
796
+ if isinstance(stmt, ir.assign_types):
794
797
  if stmt.target.name == target_list:
795
798
  region = (bt, (idx, stmt))
796
799
  return region
@@ -812,8 +815,8 @@ def peep_hole_list_to_tuple(func_ir):
812
815
  # Walk through the peep_hole and find things that are being
813
816
  # "extend"ed and "append"ed to the BUILD_LIST
814
817
  for x in peep_hole:
815
- if isinstance(x, ir.Assign):
816
- if isinstance(x.value, ir.Expr):
818
+ if isinstance(x, ir.assign_types):
819
+ if isinstance(x.value, ir.expr_types):
817
820
  expr = x.value
818
821
  if (
819
822
  expr.op == "getattr"
@@ -857,8 +860,8 @@ def peep_hole_list_to_tuple(func_ir):
857
860
  t2l_agn = region[0][1]
858
861
  acc = the_build_list
859
862
  for x in peep_hole:
860
- if isinstance(x, ir.Assign):
861
- if isinstance(x.value, ir.Expr):
863
+ if isinstance(x, ir.assign_types):
864
+ if isinstance(x.value, ir.expr_types):
862
865
  expr = x.value
863
866
  if expr.op == "getattr":
864
867
  if (
@@ -877,7 +880,7 @@ def peep_hole_list_to_tuple(func_ir):
877
880
  fname = expr.func.name
878
881
  if fname in extends or fname in appends:
879
882
  arg = expr.args[0]
880
- if isinstance(arg, ir.Var):
883
+ if isinstance(arg, ir.var_types):
881
884
  tmp_name = "%s_var_%s" % (
882
885
  fname,
883
886
  arg.name,
@@ -997,14 +1000,15 @@ def peep_hole_delete_with_exit(func_ir):
997
1000
  # Any assignment that uses any of the dead variable is considered
998
1001
  # dead.
999
1002
  if used & dead_vars:
1000
- if isinstance(stmt, ir.Assign):
1003
+ if isinstance(stmt, ir.assign_types):
1001
1004
  dead_vars.add(stmt.target)
1002
1005
 
1003
- new_body = []
1004
- for stmt in blk.body:
1006
+ new_body = [
1007
+ stmt
1008
+ for stmt in blk.body
1005
1009
  # Skip any statements that uses anyone of the dead variable.
1006
- if not (set(stmt.list_vars()) & dead_vars):
1007
- new_body.append(stmt)
1010
+ if not (set(stmt.list_vars()) & dead_vars)
1011
+ ]
1008
1012
  blk.body.clear()
1009
1013
  blk.body.extend(new_body)
1010
1014
 
@@ -1112,7 +1116,9 @@ def peep_hole_fuse_dict_add_updates(func_ir):
1112
1116
  # vars in statement. This is always the lhs with
1113
1117
  # a build_map.
1114
1118
  stmt_build_map_out = None
1115
- if isinstance(stmt, ir.Assign) and isinstance(stmt.value, ir.Expr):
1119
+ if isinstance(stmt, ir.assign_types) and isinstance(
1120
+ stmt.value, ir.expr_types
1121
+ ):
1116
1122
  if stmt.value.op == "build_map":
1117
1123
  # Skip the output build_map when looking for used vars.
1118
1124
  stmt_build_map_out = stmt.target.name
@@ -1130,9 +1136,9 @@ def peep_hole_fuse_dict_add_updates(func_ir):
1130
1136
  getattr_stmt = blk.body[i - 1]
1131
1137
  args = stmt.value.args
1132
1138
  if (
1133
- isinstance(getattr_stmt, ir.Assign)
1139
+ isinstance(getattr_stmt, ir.assign_types)
1134
1140
  and getattr_stmt.target.name == func_name
1135
- and isinstance(getattr_stmt.value, ir.Expr)
1141
+ and isinstance(getattr_stmt.value, ir.expr_types)
1136
1142
  and getattr_stmt.value.op == "getattr"
1137
1143
  and getattr_stmt.value.attr
1138
1144
  in ("__setitem__", "_update_from_bytecode")
@@ -1207,8 +1213,8 @@ def peep_hole_fuse_dict_add_updates(func_ir):
1207
1213
  # will be removed when handling their call in the next
1208
1214
  # iteration.
1209
1215
  if not (
1210
- isinstance(stmt, ir.Assign)
1211
- and isinstance(stmt.value, ir.Expr)
1216
+ isinstance(stmt, ir.assign_types)
1217
+ and isinstance(stmt.value, ir.expr_types)
1212
1218
  and stmt.value.op == "getattr"
1213
1219
  and stmt.value.value.name in lit_map_use_idx
1214
1220
  and stmt.value.attr in ("__setitem__", "_update_from_bytecode")
@@ -1249,7 +1255,7 @@ def peep_hole_split_at_pop_block(func_ir):
1249
1255
  # Gather locations of PopBlock
1250
1256
  pop_block_locs = []
1251
1257
  for i, inst in enumerate(blk.body):
1252
- if isinstance(inst, ir.PopBlock):
1258
+ if isinstance(inst, ir.popblock_types):
1253
1259
  pop_block_locs.append(i)
1254
1260
  # Rewrite block with PopBlock
1255
1261
  if pop_block_locs:
@@ -1301,10 +1307,14 @@ def _build_new_build_map(func_ir, name, old_body, old_lineno, new_items):
1301
1307
  for pair in new_items:
1302
1308
  k, v = pair
1303
1309
  key_def = ir_utils.guard(ir_utils.get_definition, func_ir, k)
1304
- if isinstance(key_def, (ir.Const, ir.Global, ir.FreeVar)):
1310
+ if isinstance(
1311
+ key_def, ir.const_types + ir.global_types + ir.freevar_types
1312
+ ):
1305
1313
  literal_keys.append(key_def.value)
1306
1314
  value_def = ir_utils.guard(ir_utils.get_definition, func_ir, v)
1307
- if isinstance(value_def, (ir.Const, ir.Global, ir.FreeVar)):
1315
+ if isinstance(
1316
+ value_def, ir.const_types + ir.global_types + ir.freevar_types
1317
+ ):
1308
1318
  values.append(value_def.value)
1309
1319
  else:
1310
1320
  # Append unknown value if not a literal.
@@ -1314,8 +1324,7 @@ def _build_new_build_map(func_ir, name, old_body, old_lineno, new_items):
1314
1324
  if len(literal_keys) == len(new_items):
1315
1325
  # All keys must be literals to have any literal values.
1316
1326
  literal_value = {x: y for x, y in zip(literal_keys, values)}
1317
- for i, k in enumerate(literal_keys):
1318
- value_indexes[k] = i
1327
+ value_indexes.update((k, i) for i, k in enumerate(literal_keys))
1319
1328
  else:
1320
1329
  literal_value = None
1321
1330
 
@@ -1381,14 +1390,14 @@ class Interpreter(object):
1381
1390
  self.current_block = None
1382
1391
  self.current_block_offset = None
1383
1392
  last_active_offset = 0
1384
- for _, inst_blocks in self.cfa.blocks.items():
1393
+ for inst_blocks in self.cfa.blocks.values():
1385
1394
  if inst_blocks.body:
1386
1395
  last_active_offset = max(
1387
1396
  last_active_offset, max(inst_blocks.body)
1388
1397
  )
1389
1398
  self.last_active_offset = last_active_offset
1390
1399
 
1391
- if PYVERSION in ((3, 12), (3, 13)):
1400
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
1392
1401
  self.active_exception_entries = tuple(
1393
1402
  [
1394
1403
  entry
@@ -1408,7 +1417,7 @@ class Interpreter(object):
1408
1417
  # Interpret loop
1409
1418
  for inst, kws in self._iter_inst():
1410
1419
  self._dispatch(inst, kws)
1411
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1420
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1412
1421
  # Insert end of try markers
1413
1422
  self._end_try_blocks()
1414
1423
  elif PYVERSION in (
@@ -1436,12 +1445,12 @@ class Interpreter(object):
1436
1445
  # post process the IR to rewrite opcodes/byte sequences that are too
1437
1446
  # involved to risk handling as part of direct interpretation
1438
1447
  peepholes = []
1439
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1448
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1440
1449
  peepholes.append(peep_hole_split_at_pop_block)
1441
- if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12), (3, 13)):
1450
+ if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
1442
1451
  peepholes.append(peep_hole_list_to_tuple)
1443
1452
  peepholes.append(peep_hole_delete_with_exit)
1444
- if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
1453
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
1445
1454
  # peep_hole_call_function_ex_to_call_function_kw
1446
1455
  # depends on peep_hole_list_to_tuple converting
1447
1456
  # any large number of arguments from a list to a
@@ -1474,7 +1483,7 @@ class Interpreter(object):
1474
1483
 
1475
1484
  See also: _insert_try_block_end
1476
1485
  """
1477
- assert PYVERSION in ((3, 11), (3, 12), (3, 13))
1486
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14))
1478
1487
  graph = self.cfa.graph
1479
1488
  for offset, block in self.blocks.items():
1480
1489
  # Get current blockstack
@@ -1514,7 +1523,7 @@ class Interpreter(object):
1514
1523
  # Propagate the exception variables to LHS of assignment
1515
1524
  for varname, defnvars in self.definitions.items():
1516
1525
  for v in defnvars:
1517
- if isinstance(v, ir.Var):
1526
+ if isinstance(v, ir.var_types):
1518
1527
  k = v.name
1519
1528
  if k in excvars:
1520
1529
  excvars.add(varname)
@@ -1582,12 +1591,12 @@ class Interpreter(object):
1582
1591
  self.dfainfo = self.dfa.infos[self.current_block_offset]
1583
1592
  self.assigner = Assigner()
1584
1593
  # Check out-of-scope syntactic-block
1585
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1594
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1586
1595
  # This is recreating pre-3.11 code structure
1587
1596
  while self.syntax_blocks:
1588
1597
  if offset >= self.syntax_blocks[-1].exit:
1589
1598
  synblk = self.syntax_blocks.pop()
1590
- if isinstance(synblk, ir.With):
1599
+ if isinstance(synblk, ir.with_types):
1591
1600
  self.current_block.append(ir.PopBlock(self.loc))
1592
1601
  else:
1593
1602
  break
@@ -1684,11 +1693,11 @@ class Interpreter(object):
1684
1693
  # like a = b[i] = 1, so need to handle replaced temporaries in
1685
1694
  # later setitem/setattr nodes
1686
1695
  if (
1687
- isinstance(inst, (ir.SetItem, ir.SetAttr))
1696
+ isinstance(inst, ir.setitem_types + ir.setattr_types)
1688
1697
  and inst.value.name in replaced_var
1689
1698
  ):
1690
1699
  inst.value = replaced_var[inst.value.name]
1691
- elif isinstance(inst, ir.Assign):
1700
+ elif isinstance(inst, ir.assign_types):
1692
1701
  if (
1693
1702
  inst.target.is_temp
1694
1703
  and inst.target.name in self.assigner.unused_dests
@@ -1698,7 +1707,7 @@ class Interpreter(object):
1698
1707
  # like a = b = 1, so need to handle replaced temporaries in
1699
1708
  # later assignments
1700
1709
  if (
1701
- isinstance(inst.value, ir.Var)
1710
+ isinstance(inst.value, ir.var_types)
1702
1711
  and inst.value.name in replaced_var
1703
1712
  ):
1704
1713
  inst.value = replaced_var[inst.value.name]
@@ -1707,7 +1716,7 @@ class Interpreter(object):
1707
1716
  # chained unpack cases may reuse temporary
1708
1717
  # e.g. a = (b, c) = (x, y)
1709
1718
  if (
1710
- isinstance(inst.value, ir.Expr)
1719
+ isinstance(inst.value, ir.expr_types)
1711
1720
  and inst.value.op == "exhaust_iter"
1712
1721
  and inst.value.value.name in replaced_var
1713
1722
  ):
@@ -1720,10 +1729,10 @@ class Interpreter(object):
1720
1729
  # the temporary variable is not reused elsewhere since CPython
1721
1730
  # bytecode is stack-based and this pattern corresponds to a pop
1722
1731
  if (
1723
- isinstance(inst.value, ir.Var)
1732
+ isinstance(inst.value, ir.var_types)
1724
1733
  and inst.value.is_temp
1725
1734
  and new_body
1726
- and isinstance(new_body[-1], ir.Assign)
1735
+ and isinstance(new_body[-1], ir.assign_types)
1727
1736
  ):
1728
1737
  prev_assign = new_body[-1]
1729
1738
  # _var_used_in_binop check makes sure we don't create a new
@@ -1753,7 +1762,7 @@ class Interpreter(object):
1753
1762
  in it as an argument
1754
1763
  """
1755
1764
  return (
1756
- isinstance(expr, ir.Expr)
1765
+ isinstance(expr, ir.expr_types)
1757
1766
  and expr.op in ("binop", "inplace_binop")
1758
1767
  and (varname == expr.lhs.name or varname == expr.rhs.name)
1759
1768
  )
@@ -1769,7 +1778,7 @@ class Interpreter(object):
1769
1778
  val = self.get(varname)
1770
1779
  except ir.NotDefinedError:
1771
1780
  # Hack to make sure exception variables are defined
1772
- assert PYVERSION in ((3, 11), (3, 12), (3, 13)), (
1781
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)), (
1773
1782
  "unexpected missing definition"
1774
1783
  )
1775
1784
  val = ir.Const(value=None, loc=self.loc)
@@ -1829,10 +1838,10 @@ class Interpreter(object):
1829
1838
  if self._DEBUG_PRINT:
1830
1839
  print(inst)
1831
1840
  assert self.current_block is not None
1832
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1841
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1833
1842
  if self.syntax_blocks:
1834
1843
  top = self.syntax_blocks[-1]
1835
- if isinstance(top, ir.With):
1844
+ if isinstance(top, ir.with_types):
1836
1845
  if inst.offset >= top.exit:
1837
1846
  self.current_block.append(ir.PopBlock(loc=self.loc))
1838
1847
  self.syntax_blocks.pop()
@@ -1881,7 +1890,7 @@ class Interpreter(object):
1881
1890
  )
1882
1891
  else:
1883
1892
  target = self.current_scope.get_or_define(name, loc=self.loc)
1884
- if isinstance(value, ir.Var):
1893
+ if isinstance(value, ir.var_types):
1885
1894
  value = self.assigner.assign(value, target)
1886
1895
  stmt = ir.Assign(value=value, target=target, loc=self.loc)
1887
1896
  self.current_block.append(stmt)
@@ -1920,6 +1929,14 @@ class Interpreter(object):
1920
1929
  def op_NOP(self, inst):
1921
1930
  pass
1922
1931
 
1932
+ if PYVERSION in ((3, 14),):
1933
+ # New in 3.14
1934
+ op_NOT_TAKEN = op_NOP
1935
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
1936
+ pass
1937
+ else:
1938
+ raise NotImplementedError(PYVERSION)
1939
+
1923
1940
  def op_RESUME(self, inst):
1924
1941
  pass
1925
1942
 
@@ -2019,7 +2036,7 @@ class Interpreter(object):
2019
2036
  )
2020
2037
  self.store(value=sliceinst, name=res)
2021
2038
 
2022
- if PYVERSION in ((3, 12), (3, 13)):
2039
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2023
2040
 
2024
2041
  def op_BINARY_SLICE(
2025
2042
  self, inst, start, end, container, res, slicevar, temp_res
@@ -2041,7 +2058,7 @@ class Interpreter(object):
2041
2058
  else:
2042
2059
  raise NotImplementedError(PYVERSION)
2043
2060
 
2044
- if PYVERSION in ((3, 12), (3, 13)):
2061
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2045
2062
 
2046
2063
  def op_STORE_SLICE(
2047
2064
  self, inst, start, end, container, value, res, slicevar
@@ -2311,7 +2328,7 @@ class Interpreter(object):
2311
2328
  srcname = self.code_locals[inst.arg]
2312
2329
  self.store(value=self.get(srcname), name=res)
2313
2330
 
2314
- if PYVERSION in ((3, 13),):
2331
+ if PYVERSION in ((3, 13), (3, 14)):
2315
2332
 
2316
2333
  def op_LOAD_FAST(self, inst, res, as_load_deref=False):
2317
2334
  if as_load_deref:
@@ -2322,7 +2339,7 @@ class Interpreter(object):
2322
2339
  else:
2323
2340
  op_LOAD_FAST = _op_LOAD_FAST
2324
2341
 
2325
- if PYVERSION in ((3, 13),):
2342
+ if PYVERSION in ((3, 13), (3, 14)):
2326
2343
 
2327
2344
  def op_LOAD_FAST_LOAD_FAST(self, inst, res1, res2):
2328
2345
  oparg = inst.arg
@@ -2360,7 +2377,7 @@ class Interpreter(object):
2360
2377
  else:
2361
2378
  raise NotImplementedError(PYVERSION)
2362
2379
 
2363
- if PYVERSION in ((3, 12), (3, 13)):
2380
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2364
2381
  op_LOAD_FAST_CHECK = op_LOAD_FAST
2365
2382
 
2366
2383
  def op_LOAD_FAST_AND_CLEAR(self, inst, res):
@@ -2378,6 +2395,16 @@ class Interpreter(object):
2378
2395
  else:
2379
2396
  raise NotImplementedError(PYVERSION)
2380
2397
 
2398
+ if PYVERSION in ((3, 14),):
2399
+ # New in 3.14.
2400
+ op_LOAD_FAST_BORROW = op_LOAD_FAST
2401
+ op_LOAD_FAST_BORROW_LOAD_FAST_BORROW = op_LOAD_FAST_LOAD_FAST
2402
+
2403
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2404
+ pass
2405
+ else:
2406
+ raise NotImplementedError(PYVERSION)
2407
+
2381
2408
  def op_STORE_FAST(self, inst, value):
2382
2409
  dstname = self.code_locals[inst.arg]
2383
2410
  value = self.get(value)
@@ -2411,7 +2438,7 @@ class Interpreter(object):
2411
2438
 
2412
2439
  def op_LOAD_ATTR(self, inst, item, res):
2413
2440
  item = self.get(item)
2414
- if PYVERSION in ((3, 12), (3, 13)):
2441
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2415
2442
  attr = self.code_names[inst.arg >> 1]
2416
2443
  elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2417
2444
  attr = self.code_names[inst.arg]
@@ -2421,28 +2448,85 @@ class Interpreter(object):
2421
2448
  self.store(getattr, res)
2422
2449
 
2423
2450
  def op_LOAD_CONST(self, inst, res):
2424
- value = self.code_consts[inst.arg]
2425
- if isinstance(value, tuple):
2451
+ # New in 3.14: slice is loaded via LOAD_CONST. The value is the
2452
+ # slice object itself, so we get the start, stop and step from it
2453
+ # directly and then proceed with the code in `BUILD_SLICE`. It may also
2454
+ # be a tuple containing a slice, so we need to account for that too.
2455
+ def process_slice(value):
2456
+ start = self.store(
2457
+ ir.Const(value.start, loc=self.loc),
2458
+ name=f"$const_{value.start}",
2459
+ redefine=True,
2460
+ )
2461
+ stop = self.store(
2462
+ ir.Const(value.stop, loc=self.loc),
2463
+ name=f"$const_{value.stop}",
2464
+ redefine=True,
2465
+ )
2466
+
2467
+ slicevar = self.store(
2468
+ value=ir.Global("slice", slice, loc=self.loc),
2469
+ name="$const_slice",
2470
+ redefine=True,
2471
+ )
2472
+
2473
+ if value.step is None:
2474
+ params = (start, stop)
2475
+ else:
2476
+ step = self.store(
2477
+ ir.Const(value.step, loc=self.loc),
2478
+ name=f"$const_{value.step}",
2479
+ redefine=True,
2480
+ )
2481
+ params = (start, stop, step)
2482
+
2483
+ return ir.Expr.call(slicevar, params, (), loc=self.loc)
2484
+
2485
+ def process_args(value):
2426
2486
  st = []
2427
2487
  for x in value:
2428
- nm = "$const_%s" % str(x)
2429
- val_const = ir.Const(x, loc=self.loc)
2430
- target = self.store(val_const, name=nm, redefine=True)
2431
- st.append(target)
2432
- const = ir.Expr.build_tuple(st, loc=self.loc)
2488
+ if isinstance(x, slice):
2489
+ st.append(
2490
+ self.store(
2491
+ process_slice(x),
2492
+ name="$const_my_slice",
2493
+ redefine=True,
2494
+ )
2495
+ )
2496
+ else:
2497
+ st.append(
2498
+ self.store(
2499
+ ir.Const(x, loc=self.loc),
2500
+ name=f"$const_{x}",
2501
+ redefine=True,
2502
+ )
2503
+ )
2504
+ return st
2505
+
2506
+ value = self.code_consts[inst.arg]
2507
+
2508
+ if isinstance(value, tuple):
2509
+ const = ir.Expr.build_tuple(process_args(value), loc=self.loc)
2433
2510
  elif isinstance(value, frozenset):
2434
- st = []
2435
- for x in value:
2436
- nm = "$const_%s" % str(x)
2437
- val_const = ir.Const(x, loc=self.loc)
2438
- target = self.store(val_const, name=nm, redefine=True)
2439
- st.append(target)
2440
- const = ir.Expr.build_set(st, loc=self.loc)
2511
+ const = ir.Expr.build_set(process_args(value), loc=self.loc)
2512
+ elif isinstance(value, slice):
2513
+ const = process_slice(value)
2441
2514
  else:
2442
2515
  const = ir.Const(value, loc=self.loc)
2443
2516
  self.store(const, res)
2444
2517
 
2445
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2518
+ if PYVERSION in ((3, 14),):
2519
+ # New in 3.14
2520
+ def op_LOAD_SMALL_INT(self, inst, res):
2521
+ value = inst.arg
2522
+ const = ir.Const(value, loc=self.loc)
2523
+ self.store(const, res)
2524
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2525
+ pass
2526
+ else:
2527
+ raise NotImplementedError(PYVERSION)
2528
+
2529
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2446
2530
 
2447
2531
  def op_LOAD_GLOBAL(self, inst, idx, res):
2448
2532
  name = self.code_names[idx]
@@ -2465,7 +2549,7 @@ class Interpreter(object):
2465
2549
  def op_COPY_FREE_VARS(self, inst):
2466
2550
  pass
2467
2551
 
2468
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2552
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2469
2553
 
2470
2554
  def op_LOAD_DEREF(self, inst, res):
2471
2555
  name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
@@ -2499,12 +2583,12 @@ class Interpreter(object):
2499
2583
  else:
2500
2584
  raise NotImplementedError(PYVERSION)
2501
2585
 
2502
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2586
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2503
2587
 
2504
2588
  def op_MAKE_CELL(self, inst):
2505
2589
  pass # ignored bytecode
2506
2590
 
2507
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2591
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2508
2592
 
2509
2593
  def op_STORE_DEREF(self, inst, value):
2510
2594
  name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
@@ -2552,39 +2636,46 @@ class Interpreter(object):
2552
2636
  exit_fn_obj = ir.Const(None, loc=self.loc)
2553
2637
  self.store(value=exit_fn_obj, name=exitfn)
2554
2638
 
2555
- def op_BEFORE_WITH(self, inst, contextmanager, exitfn, end):
2556
- assert self.blocks[inst.offset] is self.current_block
2557
- if PYVERSION in ((3, 12), (3, 13)):
2558
- # Python 3.12 hack for handling nested with blocks
2559
- if end > self.last_active_offset:
2560
- # Use exception entries to figure out end of syntax block
2561
- end = max(
2562
- [
2563
- ex.end
2564
- for ex in self.active_exception_entries
2565
- if ex.target == end
2566
- ]
2639
+ if PYVERSION in ((3, 14),):
2640
+ # Replaced by LOAD_SPECIAL in 3.14.
2641
+ pass
2642
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2643
+
2644
+ def op_BEFORE_WITH(self, inst, contextmanager, exitfn, end):
2645
+ assert self.blocks[inst.offset] is self.current_block
2646
+ if PYVERSION in ((3, 12), (3, 13)):
2647
+ # Python 3.12 hack for handling nested with blocks
2648
+ if end > self.last_active_offset:
2649
+ # Use exception entries to figure out end of syntax block
2650
+ end = max(
2651
+ [
2652
+ ex.end
2653
+ for ex in self.active_exception_entries
2654
+ if ex.target == end
2655
+ ]
2656
+ )
2657
+ elif PYVERSION in ((3, 10), (3, 11)):
2658
+ pass
2659
+ else:
2660
+ raise NotImplementedError(PYVERSION)
2661
+ # Handle with
2662
+ wth = ir.With(inst.offset, exit=end)
2663
+ self.syntax_blocks.append(wth)
2664
+ ctxmgr = self.get(contextmanager)
2665
+ self.current_block.append(
2666
+ ir.EnterWith(
2667
+ contextmanager=ctxmgr,
2668
+ begin=inst.offset,
2669
+ end=end,
2670
+ loc=self.loc,
2567
2671
  )
2568
- elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2569
- pass
2570
- else:
2571
- raise NotImplementedError(PYVERSION)
2572
- # Handle with
2573
- wth = ir.With(inst.offset, exit=end)
2574
- self.syntax_blocks.append(wth)
2575
- ctxmgr = self.get(contextmanager)
2576
- self.current_block.append(
2577
- ir.EnterWith(
2578
- contextmanager=ctxmgr,
2579
- begin=inst.offset,
2580
- end=end,
2581
- loc=self.loc,
2582
2672
  )
2583
- )
2584
2673
 
2585
- # Store exit function
2586
- exit_fn_obj = ir.Const(None, loc=self.loc)
2587
- self.store(value=exit_fn_obj, name=exitfn)
2674
+ # Store exit function
2675
+ exit_fn_obj = ir.Const(None, loc=self.loc)
2676
+ self.store(value=exit_fn_obj, name=exitfn)
2677
+ else:
2678
+ raise NotImplementedError(PYVERSION)
2588
2679
 
2589
2680
  def op_SETUP_FINALLY(self, inst):
2590
2681
  # Removed since python3.11
@@ -2623,7 +2714,7 @@ class Interpreter(object):
2623
2714
  expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
2624
2715
  self.store(expr, res)
2625
2716
 
2626
- if PYVERSION in ((3, 13),):
2717
+ if PYVERSION in ((3, 13), (3, 14)):
2627
2718
 
2628
2719
  def op_CALL_KW(self, inst, func, args, kw_names, res):
2629
2720
  func = self.get(func)
@@ -2649,7 +2740,7 @@ class Interpreter(object):
2649
2740
  # Find names const
2650
2741
  names = self.get(names)
2651
2742
  for inst in self.current_block.body:
2652
- if isinstance(inst, ir.Assign) and inst.target is names:
2743
+ if isinstance(inst, ir.assign_types) and inst.target is names:
2653
2744
  self.current_block.remove(inst)
2654
2745
  # scan up the block looking for the values, remove them
2655
2746
  # and find their name strings
@@ -2750,7 +2841,7 @@ class Interpreter(object):
2750
2841
  keyvar = self.get(keys)
2751
2842
  # TODO: refactor this pattern. occurred several times.
2752
2843
  for inst in self.current_block.body:
2753
- if isinstance(inst, ir.Assign) and inst.target is keyvar:
2844
+ if isinstance(inst, ir.assign_types) and inst.target is keyvar:
2754
2845
  self.current_block.remove(inst)
2755
2846
  # scan up the block looking for the values, remove them
2756
2847
  # and find their name strings
@@ -2776,7 +2867,7 @@ class Interpreter(object):
2776
2867
  if len(defns) != 1:
2777
2868
  break
2778
2869
  defn = defns[0]
2779
- if not isinstance(defn, ir.Const):
2870
+ if not isinstance(defn, ir.const_types):
2780
2871
  break
2781
2872
  literal_items.append(defn.value)
2782
2873
 
@@ -2785,7 +2876,7 @@ class Interpreter(object):
2785
2876
  if len(defns) != 1:
2786
2877
  return _UNKNOWN_VALUE(self.get(v).name)
2787
2878
  defn = defns[0]
2788
- if not isinstance(defn, ir.Const):
2879
+ if not isinstance(defn, ir.const_types):
2789
2880
  return _UNKNOWN_VALUE(self.get(v).name)
2790
2881
  return defn.value
2791
2882
 
@@ -2798,9 +2889,7 @@ class Interpreter(object):
2798
2889
  # store the index of the actual used value for a given key, this is
2799
2890
  # used when lowering to pull the right value out into the tuple repr
2800
2891
  # of a mixed value type dictionary.
2801
- value_indexes = {}
2802
- for i, k in enumerate(keytup):
2803
- value_indexes[k] = i
2892
+ value_indexes = {k: i for i, k in enumerate(keytup)}
2804
2893
 
2805
2894
  expr = ir.Expr.build_map(
2806
2895
  items=items,
@@ -2843,11 +2932,18 @@ class Interpreter(object):
2843
2932
  )
2844
2933
  self.current_block.append(br)
2845
2934
 
2846
- def op_BINARY_SUBSCR(self, inst, target, index, res):
2847
- index = self.get(index)
2848
- target = self.get(target)
2849
- expr = ir.Expr.getitem(target, index=index, loc=self.loc)
2850
- self.store(expr, res)
2935
+ if PYVERSION in ((3, 14),):
2936
+ # Removed in 3.14 -- replaced with BINARY_OP and []
2937
+ pass
2938
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2939
+
2940
+ def op_BINARY_SUBSCR(self, inst, target, index, res):
2941
+ index = self.get(index)
2942
+ target = self.get(target)
2943
+ expr = ir.Expr.getitem(target, index=index, loc=self.loc)
2944
+ self.store(expr, res)
2945
+ else:
2946
+ raise NotImplementedError(PYVERSION)
2851
2947
 
2852
2948
  def op_STORE_SUBSCR(self, inst, target, index, value):
2853
2949
  index = self.get(index)
@@ -2880,6 +2976,14 @@ class Interpreter(object):
2880
2976
  )
2881
2977
  self.store(expr, res)
2882
2978
 
2979
+ def op_SET_ADD(self, inst, value, target, addvar, res):
2980
+ value = self.get(value)
2981
+ target = self.get(target)
2982
+ addattr = ir.Expr.getattr(target, "add", loc=self.loc)
2983
+ self.store(value=addattr, name=addvar)
2984
+ addinst = ir.Expr.call(self.get(addvar), (value,), (), loc=self.loc)
2985
+ self.store(value=addinst, name=res)
2986
+
2883
2987
  def op_SET_UPDATE(self, inst, target, value, updatevar, res):
2884
2988
  target = self.get(target)
2885
2989
  value = self.get(value)
@@ -2921,7 +3025,7 @@ class Interpreter(object):
2921
3025
  if len(defns) != 1:
2922
3026
  break
2923
3027
  defn = defns[0]
2924
- if not isinstance(defn, ir.Const):
3028
+ if not isinstance(defn, ir.const_types):
2925
3029
  break
2926
3030
  literal_items.append(defn.value)
2927
3031
  return literal_items
@@ -2939,12 +3043,10 @@ class Interpreter(object):
2939
3043
  literal_dict = {
2940
3044
  x: _UNKNOWN_VALUE(y[1]) for x, y in zip(literal_keys, got_items)
2941
3045
  }
2942
- for i, k in enumerate(literal_keys):
2943
- value_indexes[k] = i
3046
+ value_indexes.update((k, i) for i, k in enumerate(literal_keys))
2944
3047
  else:
2945
3048
  literal_dict = {x: y for x, y in zip(literal_keys, literal_values)}
2946
- for i, k in enumerate(literal_keys):
2947
- value_indexes[k] = i
3049
+ value_indexes.update((k, i) for i, k in enumerate(literal_keys))
2948
3050
 
2949
3051
  expr = ir.Expr.build_map(
2950
3052
  items=got_items,
@@ -3000,7 +3102,13 @@ class Interpreter(object):
3000
3102
  self.store(expr, res)
3001
3103
 
3002
3104
  def op_BINARY_OP(self, inst, op, lhs, rhs, res):
3003
- if "=" in op:
3105
+ if op == "[]":
3106
+ # Special case 3.14 -- body of BINARY_SUBSCR now here
3107
+ lhs = self.get(lhs)
3108
+ rhs = self.get(rhs)
3109
+ expr = ir.Expr.getitem(lhs, index=rhs, loc=self.loc)
3110
+ self.store(expr, res)
3111
+ elif "=" in op:
3004
3112
  self._inplace_binop(op[:-1], lhs, rhs, res)
3005
3113
  else:
3006
3114
  self._binop(op, lhs, rhs, res)
@@ -3117,7 +3225,7 @@ class Interpreter(object):
3117
3225
  ret = ir.Return(self.get(castval), loc=self.loc)
3118
3226
  self.current_block.append(ret)
3119
3227
 
3120
- if PYVERSION in ((3, 12), (3, 13)):
3228
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3121
3229
 
3122
3230
  def op_RETURN_CONST(self, inst, retval, castval):
3123
3231
  value = self.code_consts[inst.arg]
@@ -3131,7 +3239,7 @@ class Interpreter(object):
3131
3239
  else:
3132
3240
  raise NotImplementedError(PYVERSION)
3133
3241
 
3134
- if PYVERSION in ((3, 13),):
3242
+ if PYVERSION in ((3, 13), (3, 14)):
3135
3243
 
3136
3244
  def op_TO_BOOL(self, inst, val, res):
3137
3245
  self.store(self.get(val), res) # TODO: just a lazy hack
@@ -3142,7 +3250,7 @@ class Interpreter(object):
3142
3250
  raise NotImplementedError(PYVERSION)
3143
3251
 
3144
3252
  def op_COMPARE_OP(self, inst, lhs, rhs, res):
3145
- if PYVERSION in ((3, 13),):
3253
+ if PYVERSION in ((3, 13), (3, 14)):
3146
3254
  op = dis.cmp_op[inst.arg >> 5]
3147
3255
  # TODO: fifth lowest bit now indicates a forced version to bool.
3148
3256
  elif PYVERSION in ((3, 12),):
@@ -3196,7 +3304,7 @@ class Interpreter(object):
3196
3304
  def op_BREAK_LOOP(self, inst, end=None):
3197
3305
  if end is None:
3198
3306
  loop = self.syntax_blocks[-1]
3199
- assert isinstance(loop, ir.Loop)
3307
+ assert isinstance(loop, ir.loop_types)
3200
3308
  end = loop.exit
3201
3309
  jmp = ir.Jump(target=end, loc=self.loc)
3202
3310
  self.current_block.append(jmp)
@@ -3271,7 +3379,7 @@ class Interpreter(object):
3271
3379
  def op_POP_JUMP_FORWARD_IF_NOT_NONE(self, inst, pred):
3272
3380
  self._jump_if_none(inst, pred, False)
3273
3381
 
3274
- if PYVERSION in ((3, 12), (3, 13)):
3382
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3275
3383
 
3276
3384
  def op_POP_JUMP_IF_NONE(self, inst, pred):
3277
3385
  self._jump_if_none(inst, pred, True)
@@ -3408,7 +3516,7 @@ class Interpreter(object):
3408
3516
  defaults = self.get(defaults)
3409
3517
 
3410
3518
  assume_code_const = self.definitions[code][0]
3411
- if not isinstance(assume_code_const, ir.Const):
3519
+ if not isinstance(assume_code_const, ir.const_types):
3412
3520
  msg = (
3413
3521
  "Unsupported use of closure. "
3414
3522
  "Probably caused by complex control-flow constructs; "
@@ -3430,7 +3538,7 @@ class Interpreter(object):
3430
3538
  inst, name, code, closure, annotations, kwdefaults, defaults, res
3431
3539
  )
3432
3540
 
3433
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
3541
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
3434
3542
 
3435
3543
  def op_LOAD_CLOSURE(self, inst, res):
3436
3544
  name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
@@ -3504,23 +3612,29 @@ class Interpreter(object):
3504
3612
 
3505
3613
  # is last emitted statement a build_tuple?
3506
3614
  stmt = self.current_block.body[-1]
3507
- ok = isinstance(stmt.value, ir.Expr) and stmt.value.op == "build_tuple"
3615
+ ok = (
3616
+ isinstance(stmt.value, ir.expr_types)
3617
+ and stmt.value.op == "build_tuple"
3618
+ )
3508
3619
  # check statements from self.current_block.body[-1] through to target,
3509
3620
  # make sure they are consts
3510
3621
  build_empty_list = None
3511
3622
  if ok:
3512
3623
  for stmt in reversed(self.current_block.body[:-1]):
3513
- if not isinstance(stmt, ir.Assign):
3624
+ if not isinstance(stmt, ir.assign_types):
3514
3625
  ok = False
3515
3626
  break
3516
3627
  # if its not a const, it needs to be the `build_list` for the
3517
3628
  # target, else it's something else we don't know about so just
3518
3629
  # bail
3519
- if isinstance(stmt.value, ir.Const):
3630
+ if isinstance(stmt.value, ir.const_types):
3520
3631
  continue
3521
3632
 
3522
3633
  # it's not a const, check for target
3523
- elif isinstance(stmt.value, ir.Expr) and stmt.target == target:
3634
+ elif (
3635
+ isinstance(stmt.value, ir.expr_types)
3636
+ and stmt.target == target
3637
+ ):
3524
3638
  build_empty_list = stmt
3525
3639
  # it's only ok to do this if the target has no initializer
3526
3640
  # already
@@ -3566,9 +3680,16 @@ class Interpreter(object):
3566
3680
  )
3567
3681
  self.store(value=appendinst, name=res)
3568
3682
 
3569
- def op_LOAD_ASSERTION_ERROR(self, inst, res):
3570
- gv_fn = ir.Global("AssertionError", AssertionError, loc=self.loc)
3571
- self.store(value=gv_fn, name=res)
3683
+ if PYVERSION in ((3, 14),):
3684
+ # Removed in 3.14
3685
+ pass
3686
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
3687
+
3688
+ def op_LOAD_ASSERTION_ERROR(self, inst, res):
3689
+ gv_fn = ir.Global("AssertionError", AssertionError, loc=self.loc)
3690
+ self.store(value=gv_fn, name=res)
3691
+ else:
3692
+ raise NotImplementedError(PYVERSION)
3572
3693
 
3573
3694
  # NOTE: The LOAD_METHOD opcode is implemented as a LOAD_ATTR for ease,
3574
3695
  # however this means a new object (the bound-method instance) could be
@@ -3584,7 +3705,7 @@ class Interpreter(object):
3584
3705
  def op_CALL_METHOD(self, *args, **kws):
3585
3706
  self.op_CALL_FUNCTION(*args, **kws)
3586
3707
 
3587
- if PYVERSION in ((3, 12), (3, 13)):
3708
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3588
3709
 
3589
3710
  def op_CALL_INTRINSIC_1(self, inst, operand, **kwargs):
3590
3711
  if operand == ci1op.INTRINSIC_STOPITERATION_ERROR:
@@ -3606,8 +3727,61 @@ class Interpreter(object):
3606
3727
  else:
3607
3728
  raise NotImplementedError(PYVERSION)
3608
3729
 
3730
+ if PYVERSION in ((3, 14),):
3731
+ # New in 3.14, replaces BEFORE_WITH.
3732
+ def op_LOAD_SPECIAL(self, inst, contextmanager, exit_method, block_end):
3733
+ assert self.blocks[inst.offset] is self.current_block
3734
+
3735
+ # Python 3.12 hack for handling nested with blocks
3736
+ if block_end > self.last_active_offset:
3737
+ # Use exception entries to figure out end of syntax block
3738
+ block_end = max(
3739
+ [
3740
+ ex.end
3741
+ for ex in self.active_exception_entries
3742
+ if ex.target == block_end
3743
+ ]
3744
+ )
3745
+
3746
+ # Handle with
3747
+ wth = ir.With(inst.offset, exit=block_end)
3748
+ self.syntax_blocks.append(wth)
3749
+ ctxmgr = self.get(contextmanager)
3750
+ self.current_block.append(
3751
+ ir.EnterWith(
3752
+ contextmanager=ctxmgr,
3753
+ begin=inst.offset,
3754
+ end=block_end,
3755
+ loc=self.loc,
3756
+ )
3757
+ )
3758
+
3759
+ # Store exit function
3760
+ exit_fn_obj = ir.Const(None, loc=self.loc)
3761
+ self.store(value=exit_fn_obj, name=exit_method)
3762
+
3763
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
3764
+ pass
3765
+ else:
3766
+ raise NotImplementedError(PYVERSION)
3767
+
3768
+ if PYVERSION in ((3, 14),):
3769
+
3770
+ def op_LOAD_COMMON_CONSTANT(self, inst, res, idx):
3771
+ if isinstance(dis._common_constants[idx], AssertionError):
3772
+ gv_fn = ir.Global(
3773
+ "AssertionError", AssertionError, loc=self.loc
3774
+ )
3775
+ self.store(value=gv_fn, name=res)
3776
+ else:
3777
+ raise NotImplementedError
3778
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
3779
+ pass
3780
+ else:
3781
+ raise NotImplementedError(PYVERSION)
3782
+
3609
3783
 
3610
- if PYVERSION in ((3, 12), (3, 13)):
3784
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3611
3785
 
3612
3786
  class INTRINSIC_STOPITERATION_ERROR(AssertionError):
3613
3787
  pass