Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1899,25 +1899,29 @@ iterations of the loop.

The operand determines which intrinsic function is called:

+----------------------------------------+-----------------------------------+
| Operand | Description |
+========================================+===================================+
| ``INTRINSIC_2_INVALID`` | Not valid |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_PREP_RERAISE_STAR`` | Calculates the |
| | :exc:`ExceptionGroup` to raise |
| | from a ``try-except*``. |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR_WITH_BOUND`` | Creates a :class:`typing.TypeVar` |
| | with a bound. |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR_WITH_CONSTRAINTS`` | Creates a |
| | :class:`typing.TypeVar` with |
| | constraints. |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_SET_FUNCTION_TYPE_PARAMS`` | Sets the ``__type_params__`` |
| | attribute of a function. |
+----------------------------------------+-----------------------------------+
+------------------------------------------+-----------------------------------+
| Operand | Description |
+==========================================+===================================+
| ``INTRINSIC_2_INVALID`` | Not valid |
+------------------------------------------+-----------------------------------+
| ``INTRINSIC_PREP_RERAISE_STAR`` | Calculates the |
| | :exc:`ExceptionGroup` to raise |
| | from a ``try-except*``. |
+------------------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR_WITH_BOUND`` | Creates a :class:`typing.TypeVar` |
| | with a bound. |
+------------------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR_WITH_CONSTRAINTS`` | Creates a |
| | :class:`typing.TypeVar` with |
| | constraints. |
+------------------------------------------+-----------------------------------+
| ``INTRINSIC_SET_FUNCTION_TYPE_PARAMS`` | Sets the ``__type_params__`` |
| | attribute of a function. |
+------------------------------------------+-----------------------------------+
| ``INTRINSIC_ADD_CONDITIONAL_ANNOTATION`` | Adds an annotation index to the |
| | ``__conditional_annotations__`` |
| | set. |
+------------------------------------------+-----------------------------------+

.. versionadded:: 3.12

Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
#define INTRINSIC_TYPEVAR_WITH_CONSTRAINTS 3
#define INTRINSIC_SET_FUNCTION_TYPE_PARAMS 4
#define INTRINSIC_SET_TYPEPARAM_DEFAULT 5
#define INTRINSIC_ADD_CONDITIONAL_ANNOTATION 6

#define MAX_INTRINSIC_2 5
#define MAX_INTRINSIC_2 6

typedef PyObject *(*intrinsic_func1)(PyThreadState* tstate, PyObject *value);
typedef PyObject *(*intrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);
Expand Down
4 changes: 2 additions & 2 deletions Include/internal/pycore_magic_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ Known values:
Python 3.16a1 3702 (Replace DELETE_NAME with PUSH_NULL; STORE_NAME)
Python 3.16a1 3703 (Replace DELETE_GLOBAL with PUSH_NULL; STORE_GLOBAL)
Python 3.16a1 3704 (Replace DELETE_ATTR with PUSH_NULL; STORE_ATTR)
Python 3.16a1 3705 (Add INTRINSIC_ADD_CONDITIONAL_ANNOTATION)
Python 3.17 will start with 3750
Expand All @@ -312,7 +312,7 @@ Known values:
*/

#define PYC_MAGIC_NUMBER 3704
#define PYC_MAGIC_NUMBER 3705
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
(little-endian) and then appending b'\r\n'. */
#define PYC_MAGIC_NUMBER_TOKEN \
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,12 @@ def wrap_func_w_kwargs():
STORE_NAME 1 (x)
LOAD_NAME 0 (__conditional_annotations__)
LOAD_SMALL_INT 0
SET_ADD 1
CALL_INTRINSIC_2 6 (INTRINSIC_ADD_CONDITIONAL_ANNOTATION)
POP_TOP
3 LOAD_NAME 0 (__conditional_annotations__)
LOAD_SMALL_INT 1
SET_ADD 1
CALL_INTRINSIC_2 6 (INTRINSIC_ADD_CONDITIONAL_ANNOTATION)
POP_TOP
4 LOAD_SMALL_INT 1
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_type_annotations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import annotationlib
import inspect
import itertools
import textwrap
import types
import unittest
Expand Down Expand Up @@ -896,3 +897,18 @@ class Generic:
mod = build_module(code)
annos = mod.__annotations__
self.assertEqual(annos, {"annotated_name": 0})

# gh-154902
def test_conditional_annotations_rebound(self):
# user code can rebind __conditional_annotations__ to any object
lefts = ("__conditional_annotations__",
'globals()["__conditional_annotations__"]')
values = ("0", "{}", "[]", "''", "object()", "frozenset()")
for left, value in itertools.product(lefts, values):
with self.subTest(left=left, value=value):
code = f"""
{left} = {value}
x: int
"""
with self.assertRaises(TypeError):
run_code(code)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix a crash when ``__conditional_annotations__`` is rebound to a non-set
object.
4 changes: 3 additions & 1 deletion Python/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -5807,7 +5807,9 @@ codegen_annassign(compiler *c, stmt_ty s)
ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__conditional_annotations__), names);
}
ADDOP_LOAD_CONST_NEW(c, loc, conditional_annotation_index);
ADDOP_I(c, loc, SET_ADD, 1);
// gh-154902: change SET_ADD to new INTRINSIC_ADD_CONDITIONAL_ANNOTATION intrinsic
ADDOP_I(c, loc, CALL_INTRINSIC_2,
INTRINSIC_ADD_CONDITIONAL_ANNOTATION);
ADDOP(c, loc, POP_TOP);
}
}
Expand Down
18 changes: 18 additions & 0 deletions Python/intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,23 @@ make_typevar_with_constraints(PyThreadState* Py_UNUSED(ignored), PyObject *name,
return _Py_make_typevar(name, NULL, evaluate_constraints);
}

static PyObject *
add_conditional_annotation(PyThreadState* tstate, PyObject *conditional_annotations,
PyObject *index)
{
// gh-154902: user code can rebind __conditional_annotations__ to any object
if (!PySet_CheckExact(conditional_annotations)) {
_PyErr_Format(tstate, PyExc_TypeError,
"__conditional_annotations__ must be a set, not %T",
conditional_annotations);
return NULL;
}
if (PySet_Add(conditional_annotations, index) < 0) {
return NULL;
}
Py_RETURN_NONE;
}

const intrinsic_func2_info
_PyIntrinsics_BinaryFunctions[] = {
INTRINSIC_FUNC_ENTRY(INTRINSIC_2_INVALID, no_intrinsic2)
Expand All @@ -278,6 +295,7 @@ _PyIntrinsics_BinaryFunctions[] = {
INTRINSIC_FUNC_ENTRY(INTRINSIC_TYPEVAR_WITH_CONSTRAINTS, make_typevar_with_constraints)
INTRINSIC_FUNC_ENTRY(INTRINSIC_SET_FUNCTION_TYPE_PARAMS, _Py_set_function_type_params)
INTRINSIC_FUNC_ENTRY(INTRINSIC_SET_TYPEPARAM_DEFAULT, _Py_set_typeparam_default)
INTRINSIC_FUNC_ENTRY(INTRINSIC_ADD_CONDITIONAL_ANNOTATION, add_conditional_annotation)
};

#undef INTRINSIC_FUNC_ENTRY
Expand Down
Loading