mirror of
https://github.com/python/cpython.git
synced 2025-08-22 17:55:18 +00:00
gh-119180: PEP 649 compiler changes (#119361)
This commit is contained in:
parent
02c1dfff07
commit
9b8611eeea
28 changed files with 610 additions and 329 deletions
|
@ -559,6 +559,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot_locals));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot_locals));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(empty));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(empty));
|
||||||
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(format));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(generic_base));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(generic_base));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults));
|
||||||
|
@ -745,7 +746,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abstract_));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abstract_));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_active));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_active));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_align_));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_align_));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_annotation));
|
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_anonymous_));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_anonymous_));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_argtypes_));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_argtypes_));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_as_parameter_));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_as_parameter_));
|
||||||
|
|
|
@ -45,6 +45,7 @@ struct _Py_global_strings {
|
||||||
STRUCT_FOR_STR(dot, ".")
|
STRUCT_FOR_STR(dot, ".")
|
||||||
STRUCT_FOR_STR(dot_locals, ".<locals>")
|
STRUCT_FOR_STR(dot_locals, ".<locals>")
|
||||||
STRUCT_FOR_STR(empty, "")
|
STRUCT_FOR_STR(empty, "")
|
||||||
|
STRUCT_FOR_STR(format, ".format")
|
||||||
STRUCT_FOR_STR(generic_base, ".generic_base")
|
STRUCT_FOR_STR(generic_base, ".generic_base")
|
||||||
STRUCT_FOR_STR(json_decoder, "json.decoder")
|
STRUCT_FOR_STR(json_decoder, "json.decoder")
|
||||||
STRUCT_FOR_STR(kwdefaults, ".kwdefaults")
|
STRUCT_FOR_STR(kwdefaults, ".kwdefaults")
|
||||||
|
@ -234,7 +235,6 @@ struct _Py_global_strings {
|
||||||
STRUCT_FOR_ID(_abstract_)
|
STRUCT_FOR_ID(_abstract_)
|
||||||
STRUCT_FOR_ID(_active)
|
STRUCT_FOR_ID(_active)
|
||||||
STRUCT_FOR_ID(_align_)
|
STRUCT_FOR_ID(_align_)
|
||||||
STRUCT_FOR_ID(_annotation)
|
|
||||||
STRUCT_FOR_ID(_anonymous_)
|
STRUCT_FOR_ID(_anonymous_)
|
||||||
STRUCT_FOR_ID(_argtypes_)
|
STRUCT_FOR_ID(_argtypes_)
|
||||||
STRUCT_FOR_ID(_as_parameter_)
|
STRUCT_FOR_ID(_as_parameter_)
|
||||||
|
|
|
@ -57,6 +57,7 @@ extern "C" {
|
||||||
#define MAKE_FUNCTION_KWDEFAULTS 0x02
|
#define MAKE_FUNCTION_KWDEFAULTS 0x02
|
||||||
#define MAKE_FUNCTION_ANNOTATIONS 0x04
|
#define MAKE_FUNCTION_ANNOTATIONS 0x04
|
||||||
#define MAKE_FUNCTION_CLOSURE 0x08
|
#define MAKE_FUNCTION_CLOSURE 0x08
|
||||||
|
#define MAKE_FUNCTION_ANNOTATE 0x10
|
||||||
|
|
||||||
/* Values used as the oparg for LOAD_COMMON_CONSTANT */
|
/* Values used as the oparg for LOAD_COMMON_CONSTANT */
|
||||||
#define CONSTANT_ASSERTIONERROR 0
|
#define CONSTANT_ASSERTIONERROR 0
|
||||||
|
|
2
Include/internal/pycore_runtime_init_generated.h
generated
2
Include/internal/pycore_runtime_init_generated.h
generated
|
@ -554,6 +554,7 @@ extern "C" {
|
||||||
INIT_STR(dot, "."), \
|
INIT_STR(dot, "."), \
|
||||||
INIT_STR(dot_locals, ".<locals>"), \
|
INIT_STR(dot_locals, ".<locals>"), \
|
||||||
INIT_STR(empty, ""), \
|
INIT_STR(empty, ""), \
|
||||||
|
INIT_STR(format, ".format"), \
|
||||||
INIT_STR(generic_base, ".generic_base"), \
|
INIT_STR(generic_base, ".generic_base"), \
|
||||||
INIT_STR(json_decoder, "json.decoder"), \
|
INIT_STR(json_decoder, "json.decoder"), \
|
||||||
INIT_STR(kwdefaults, ".kwdefaults"), \
|
INIT_STR(kwdefaults, ".kwdefaults"), \
|
||||||
|
@ -743,7 +744,6 @@ extern "C" {
|
||||||
INIT_ID(_abstract_), \
|
INIT_ID(_abstract_), \
|
||||||
INIT_ID(_active), \
|
INIT_ID(_active), \
|
||||||
INIT_ID(_align_), \
|
INIT_ID(_align_), \
|
||||||
INIT_ID(_annotation), \
|
|
||||||
INIT_ID(_anonymous_), \
|
INIT_ID(_anonymous_), \
|
||||||
INIT_ID(_argtypes_), \
|
INIT_ID(_argtypes_), \
|
||||||
INIT_ID(_as_parameter_), \
|
INIT_ID(_as_parameter_), \
|
||||||
|
|
|
@ -12,8 +12,9 @@ struct _mod; // Type defined in pycore_ast.h
|
||||||
|
|
||||||
typedef enum _block_type {
|
typedef enum _block_type {
|
||||||
FunctionBlock, ClassBlock, ModuleBlock,
|
FunctionBlock, ClassBlock, ModuleBlock,
|
||||||
// Used for annotations if 'from __future__ import annotations' is active.
|
// Used for annotations. If 'from __future__ import annotations' is active,
|
||||||
// Annotation blocks cannot bind names and are not evaluated.
|
// annotation blocks cannot bind names and are not evaluated. Otherwise, they
|
||||||
|
// are lazily evaluated (see PEP 649).
|
||||||
AnnotationBlock,
|
AnnotationBlock,
|
||||||
// Used for generics and type aliases. These work mostly like functions
|
// Used for generics and type aliases. These work mostly like functions
|
||||||
// (see PEP 695 for details). The three different blocks function identically;
|
// (see PEP 695 for details). The three different blocks function identically;
|
||||||
|
@ -89,6 +90,7 @@ typedef struct _symtable_entry {
|
||||||
including free refs to globals */
|
including free refs to globals */
|
||||||
unsigned ste_generator : 1; /* true if namespace is a generator */
|
unsigned ste_generator : 1; /* true if namespace is a generator */
|
||||||
unsigned ste_coroutine : 1; /* true if namespace is a coroutine */
|
unsigned ste_coroutine : 1; /* true if namespace is a coroutine */
|
||||||
|
unsigned ste_annotations_used : 1; /* true if there are any annotations in this scope */
|
||||||
_Py_comprehension_ty ste_comprehension; /* Kind of comprehension (if any) */
|
_Py_comprehension_ty ste_comprehension; /* Kind of comprehension (if any) */
|
||||||
unsigned ste_varargs : 1; /* true if block has varargs */
|
unsigned ste_varargs : 1; /* true if block has varargs */
|
||||||
unsigned ste_varkeywords : 1; /* true if block has varkeywords */
|
unsigned ste_varkeywords : 1; /* true if block has varkeywords */
|
||||||
|
@ -110,6 +112,7 @@ typedef struct _symtable_entry {
|
||||||
int ste_end_col_offset; /* end offset of first line of block */
|
int ste_end_col_offset; /* end offset of first line of block */
|
||||||
int ste_opt_lineno; /* lineno of last exec or import * */
|
int ste_opt_lineno; /* lineno of last exec or import * */
|
||||||
int ste_opt_col_offset; /* offset of last exec or import * */
|
int ste_opt_col_offset; /* offset of last exec or import * */
|
||||||
|
struct _symtable_entry *ste_annotation_block; /* symbol table entry for this entry's annotations */
|
||||||
struct symtable *ste_table;
|
struct symtable *ste_table;
|
||||||
} PySTEntryObject;
|
} PySTEntryObject;
|
||||||
|
|
||||||
|
@ -126,6 +129,7 @@ extern struct symtable* _PySymtable_Build(
|
||||||
PyObject *filename,
|
PyObject *filename,
|
||||||
_PyFutureFeatures *future);
|
_PyFutureFeatures *future);
|
||||||
extern PySTEntryObject* _PySymtable_Lookup(struct symtable *, void *);
|
extern PySTEntryObject* _PySymtable_Lookup(struct symtable *, void *);
|
||||||
|
extern int _PySymtable_LookupOptional(struct symtable *, void *, PySTEntryObject **);
|
||||||
|
|
||||||
extern void _PySymtable_Free(struct symtable *);
|
extern void _PySymtable_Free(struct symtable *);
|
||||||
|
|
||||||
|
|
|
@ -543,9 +543,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
||||||
string = &_Py_ID(_align_);
|
string = &_Py_ID(_align_);
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
_PyUnicode_InternInPlace(interp, &string);
|
_PyUnicode_InternInPlace(interp, &string);
|
||||||
string = &_Py_ID(_annotation);
|
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
|
||||||
_PyUnicode_InternInPlace(interp, &string);
|
|
||||||
string = &_Py_ID(_anonymous_);
|
string = &_Py_ID(_anonymous_);
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
_PyUnicode_InternInPlace(interp, &string);
|
_PyUnicode_InternInPlace(interp, &string);
|
||||||
|
|
|
@ -220,13 +220,7 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False):
|
||||||
"""
|
"""
|
||||||
if isinstance(obj, type):
|
if isinstance(obj, type):
|
||||||
# class
|
# class
|
||||||
obj_dict = getattr(obj, '__dict__', None)
|
ann = obj.__annotations__
|
||||||
if obj_dict and hasattr(obj_dict, 'get'):
|
|
||||||
ann = obj_dict.get('__annotations__', None)
|
|
||||||
if isinstance(ann, types.GetSetDescriptorType):
|
|
||||||
ann = None
|
|
||||||
else:
|
|
||||||
ann = None
|
|
||||||
|
|
||||||
obj_globals = None
|
obj_globals = None
|
||||||
module_name = getattr(obj, '__module__', None)
|
module_name = getattr(obj, '__module__', None)
|
||||||
|
|
|
@ -222,6 +222,8 @@ class Class(SymbolTable):
|
||||||
if self.__methods is None:
|
if self.__methods is None:
|
||||||
d = {}
|
d = {}
|
||||||
for st in self._table.children:
|
for st in self._table.children:
|
||||||
|
if st.type == _symtable.TYPE_ANNOTATION:
|
||||||
|
continue
|
||||||
d[st.name] = 1
|
d[st.name] = 1
|
||||||
self.__methods = tuple(d)
|
self.__methods = tuple(d)
|
||||||
return self.__methods
|
return self.__methods
|
||||||
|
|
|
@ -352,32 +352,21 @@ lst[fun(0)]: int = 1
|
||||||
dis_annot_stmt_str = """\
|
dis_annot_stmt_str = """\
|
||||||
0 RESUME 0
|
0 RESUME 0
|
||||||
|
|
||||||
2 SETUP_ANNOTATIONS
|
2 LOAD_CONST 0 (1)
|
||||||
LOAD_CONST 0 (1)
|
|
||||||
STORE_NAME 0 (x)
|
STORE_NAME 0 (x)
|
||||||
LOAD_NAME 1 (int)
|
|
||||||
LOAD_NAME 2 (__annotations__)
|
|
||||||
LOAD_CONST 1 ('x')
|
|
||||||
STORE_SUBSCR
|
|
||||||
|
|
||||||
3 LOAD_NAME 3 (fun)
|
|
||||||
PUSH_NULL
|
|
||||||
LOAD_CONST 0 (1)
|
|
||||||
CALL 1
|
|
||||||
LOAD_NAME 2 (__annotations__)
|
|
||||||
LOAD_CONST 2 ('y')
|
|
||||||
STORE_SUBSCR
|
|
||||||
|
|
||||||
4 LOAD_CONST 0 (1)
|
4 LOAD_CONST 0 (1)
|
||||||
LOAD_NAME 4 (lst)
|
LOAD_NAME 1 (lst)
|
||||||
LOAD_NAME 3 (fun)
|
LOAD_NAME 2 (fun)
|
||||||
PUSH_NULL
|
PUSH_NULL
|
||||||
LOAD_CONST 3 (0)
|
LOAD_CONST 1 (0)
|
||||||
CALL 1
|
CALL 1
|
||||||
STORE_SUBSCR
|
STORE_SUBSCR
|
||||||
LOAD_NAME 1 (int)
|
|
||||||
POP_TOP
|
2 LOAD_CONST 2 (<code object __annotate__ at 0x..., file "<dis>", line 2>)
|
||||||
RETURN_CONST 4 (None)
|
MAKE_FUNCTION
|
||||||
|
STORE_NAME 3 (__annotate__)
|
||||||
|
RETURN_CONST 3 (None)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
compound_stmt_str = """\
|
compound_stmt_str = """\
|
||||||
|
|
|
@ -306,16 +306,6 @@ the \'lazy\' dog.\n\
|
||||||
|
|
||||||
var_annot_global: int # a global annotated is necessary for test_var_annot
|
var_annot_global: int # a global annotated is necessary for test_var_annot
|
||||||
|
|
||||||
# custom namespace for testing __annotations__
|
|
||||||
|
|
||||||
class CNS:
|
|
||||||
def __init__(self):
|
|
||||||
self._dct = {}
|
|
||||||
def __setitem__(self, item, value):
|
|
||||||
self._dct[item.lower()] = value
|
|
||||||
def __getitem__(self, item):
|
|
||||||
return self._dct[item]
|
|
||||||
|
|
||||||
|
|
||||||
class GrammarTests(unittest.TestCase):
|
class GrammarTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -446,22 +436,12 @@ class GrammarTests(unittest.TestCase):
|
||||||
self.assertEqual(E.__annotations__, {})
|
self.assertEqual(E.__annotations__, {})
|
||||||
self.assertEqual(F.__annotations__, {})
|
self.assertEqual(F.__annotations__, {})
|
||||||
|
|
||||||
|
|
||||||
def test_var_annot_metaclass_semantics(self):
|
|
||||||
class CMeta(type):
|
|
||||||
@classmethod
|
|
||||||
def __prepare__(metacls, name, bases, **kwds):
|
|
||||||
return {'__annotations__': CNS()}
|
|
||||||
class CC(metaclass=CMeta):
|
|
||||||
XX: 'ANNOT'
|
|
||||||
self.assertEqual(CC.__annotations__['xx'], 'ANNOT')
|
|
||||||
|
|
||||||
def test_var_annot_module_semantics(self):
|
def test_var_annot_module_semantics(self):
|
||||||
self.assertEqual(test.__annotations__, {})
|
self.assertEqual(test.__annotations__, {})
|
||||||
self.assertEqual(ann_module.__annotations__,
|
self.assertEqual(ann_module.__annotations__,
|
||||||
{1: 2, 'x': int, 'y': str, 'f': typing.Tuple[int, int], 'u': int | float})
|
{'x': int, 'y': str, 'f': typing.Tuple[int, int], 'u': int | float})
|
||||||
self.assertEqual(ann_module.M.__annotations__,
|
self.assertEqual(ann_module.M.__annotations__,
|
||||||
{'123': 123, 'o': type})
|
{'o': type})
|
||||||
self.assertEqual(ann_module2.__annotations__, {})
|
self.assertEqual(ann_module2.__annotations__, {})
|
||||||
|
|
||||||
def test_var_annot_in_module(self):
|
def test_var_annot_in_module(self):
|
||||||
|
@ -476,51 +456,12 @@ class GrammarTests(unittest.TestCase):
|
||||||
ann_module3.D_bad_ann(5)
|
ann_module3.D_bad_ann(5)
|
||||||
|
|
||||||
def test_var_annot_simple_exec(self):
|
def test_var_annot_simple_exec(self):
|
||||||
gns = {}; lns= {}
|
gns = {}; lns = {}
|
||||||
exec("'docstring'\n"
|
exec("'docstring'\n"
|
||||||
"__annotations__[1] = 2\n"
|
|
||||||
"x: int = 5\n", gns, lns)
|
"x: int = 5\n", gns, lns)
|
||||||
self.assertEqual(lns["__annotations__"], {1: 2, 'x': int})
|
self.assertEqual(lns["__annotate__"](1), {'x': int})
|
||||||
with self.assertRaises(KeyError):
|
with self.assertRaises(KeyError):
|
||||||
gns['__annotations__']
|
gns['__annotate__']
|
||||||
|
|
||||||
def test_var_annot_custom_maps(self):
|
|
||||||
# tests with custom locals() and __annotations__
|
|
||||||
ns = {'__annotations__': CNS()}
|
|
||||||
exec('X: int; Z: str = "Z"; (w): complex = 1j', ns)
|
|
||||||
self.assertEqual(ns['__annotations__']['x'], int)
|
|
||||||
self.assertEqual(ns['__annotations__']['z'], str)
|
|
||||||
with self.assertRaises(KeyError):
|
|
||||||
ns['__annotations__']['w']
|
|
||||||
nonloc_ns = {}
|
|
||||||
class CNS2:
|
|
||||||
def __init__(self):
|
|
||||||
self._dct = {}
|
|
||||||
def __setitem__(self, item, value):
|
|
||||||
nonlocal nonloc_ns
|
|
||||||
self._dct[item] = value
|
|
||||||
nonloc_ns[item] = value
|
|
||||||
def __getitem__(self, item):
|
|
||||||
return self._dct[item]
|
|
||||||
exec('x: int = 1', {}, CNS2())
|
|
||||||
self.assertEqual(nonloc_ns['__annotations__']['x'], int)
|
|
||||||
|
|
||||||
def test_var_annot_refleak(self):
|
|
||||||
# complex case: custom locals plus custom __annotations__
|
|
||||||
# this was causing refleak
|
|
||||||
cns = CNS()
|
|
||||||
nonloc_ns = {'__annotations__': cns}
|
|
||||||
class CNS2:
|
|
||||||
def __init__(self):
|
|
||||||
self._dct = {'__annotations__': cns}
|
|
||||||
def __setitem__(self, item, value):
|
|
||||||
nonlocal nonloc_ns
|
|
||||||
self._dct[item] = value
|
|
||||||
nonloc_ns[item] = value
|
|
||||||
def __getitem__(self, item):
|
|
||||||
return self._dct[item]
|
|
||||||
exec('X: str', {}, CNS2())
|
|
||||||
self.assertEqual(nonloc_ns['__annotations__']['x'], str)
|
|
||||||
|
|
||||||
def test_var_annot_rhs(self):
|
def test_var_annot_rhs(self):
|
||||||
ns = {}
|
ns = {}
|
||||||
|
|
|
@ -360,6 +360,8 @@ a = A(destroyed)"""
|
||||||
ann_module4 = import_helper.import_fresh_module(
|
ann_module4 = import_helper.import_fresh_module(
|
||||||
'test.typinganndata.ann_module4',
|
'test.typinganndata.ann_module4',
|
||||||
)
|
)
|
||||||
|
self.assertFalse("__annotations__" in ann_module4.__dict__)
|
||||||
|
self.assertEqual(ann_module4.__annotations__, {"a": int, "b": str})
|
||||||
self.assertTrue("__annotations__" in ann_module4.__dict__)
|
self.assertTrue("__annotations__" in ann_module4.__dict__)
|
||||||
del ann_module4.__annotations__
|
del ann_module4.__annotations__
|
||||||
self.assertFalse("__annotations__" in ann_module4.__dict__)
|
self.assertFalse("__annotations__" in ann_module4.__dict__)
|
||||||
|
|
|
@ -39,16 +39,19 @@ class OpcodeTest(unittest.TestCase):
|
||||||
def test_use_existing_annotations(self):
|
def test_use_existing_annotations(self):
|
||||||
ns = {'__annotations__': {1: 2}}
|
ns = {'__annotations__': {1: 2}}
|
||||||
exec('x: int', ns)
|
exec('x: int', ns)
|
||||||
self.assertEqual(ns['__annotations__'], {'x': int, 1: 2})
|
self.assertEqual(ns['__annotations__'], {1: 2})
|
||||||
|
|
||||||
def test_do_not_recreate_annotations(self):
|
def test_do_not_recreate_annotations(self):
|
||||||
# Don't rely on the existence of the '__annotations__' global.
|
# Don't rely on the existence of the '__annotations__' global.
|
||||||
with support.swap_item(globals(), '__annotations__', {}):
|
with support.swap_item(globals(), '__annotations__', {}):
|
||||||
del globals()['__annotations__']
|
globals().pop('__annotations__', None)
|
||||||
class C:
|
class C:
|
||||||
del __annotations__
|
try:
|
||||||
with self.assertRaises(NameError):
|
del __annotations__
|
||||||
x: int
|
except NameError:
|
||||||
|
pass
|
||||||
|
x: int
|
||||||
|
self.assertEqual(C.__annotations__, {"x": int})
|
||||||
|
|
||||||
def test_raise_class_exceptions(self):
|
def test_raise_class_exceptions(self):
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import dis
|
import dis
|
||||||
import pickle
|
import pickle
|
||||||
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from test.support import check_syntax_error
|
from test.support import check_syntax_error
|
||||||
|
@ -440,7 +441,9 @@ class PositionalOnlyTestCase(unittest.TestCase):
|
||||||
# without constant folding we end up with
|
# without constant folding we end up with
|
||||||
# COMPARE_OP(is), IS_OP (0)
|
# COMPARE_OP(is), IS_OP (0)
|
||||||
# with constant folding we should expect a IS_OP (1)
|
# with constant folding we should expect a IS_OP (1)
|
||||||
codes = [(i.opname, i.argval) for i in dis.get_instructions(g)]
|
code_obj = next(const for const in g.__code__.co_consts
|
||||||
|
if isinstance(const, types.CodeType) and const.co_name == "__annotate__")
|
||||||
|
codes = [(i.opname, i.argval) for i in dis.get_instructions(code_obj)]
|
||||||
self.assertNotIn(('UNARY_NOT', None), codes)
|
self.assertNotIn(('UNARY_NOT', None), codes)
|
||||||
self.assertIn(('IS_OP', 1), codes)
|
self.assertIn(('IS_OP', 1), codes)
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,8 @@ class PyclbrTest(TestCase):
|
||||||
|
|
||||||
actualMethods = []
|
actualMethods = []
|
||||||
for m in py_item.__dict__.keys():
|
for m in py_item.__dict__.keys():
|
||||||
|
if m == "__annotate__":
|
||||||
|
continue
|
||||||
if ismethod(py_item, getattr(py_item, m), m):
|
if ismethod(py_item, getattr(py_item, m), m):
|
||||||
actualMethods.append(m)
|
actualMethods.append(m)
|
||||||
foundMethods = []
|
foundMethods = []
|
||||||
|
|
|
@ -77,6 +77,11 @@ CLASSES
|
||||||
| __weakref__%s
|
| __weakref__%s
|
||||||
|
|
||||||
class B(builtins.object)
|
class B(builtins.object)
|
||||||
|
| Methods defined here:
|
||||||
|
|
|
||||||
|
| __annotate__(...)
|
||||||
|
|
|
||||||
|
| ----------------------------------------------------------------------
|
||||||
| Data descriptors defined here:
|
| Data descriptors defined here:
|
||||||
|
|
|
|
||||||
| __dict__%s
|
| __dict__%s
|
||||||
|
@ -87,8 +92,6 @@ CLASSES
|
||||||
| Data and other attributes defined here:
|
| Data and other attributes defined here:
|
||||||
|
|
|
|
||||||
| NO_MEANING = 'eggs'
|
| NO_MEANING = 'eggs'
|
||||||
|
|
|
||||||
| __annotations__ = {'NO_MEANING': <class 'str'>}
|
|
||||||
|
|
||||||
class C(builtins.object)
|
class C(builtins.object)
|
||||||
| Methods defined here:
|
| Methods defined here:
|
||||||
|
@ -176,6 +179,9 @@ class A(builtins.object)
|
||||||
list of weak references to the object
|
list of weak references to the object
|
||||||
|
|
||||||
class B(builtins.object)
|
class B(builtins.object)
|
||||||
|
Methods defined here:
|
||||||
|
__annotate__(...)
|
||||||
|
----------------------------------------------------------------------
|
||||||
Data descriptors defined here:
|
Data descriptors defined here:
|
||||||
__dict__
|
__dict__
|
||||||
dictionary for instance variables
|
dictionary for instance variables
|
||||||
|
@ -184,7 +190,6 @@ class B(builtins.object)
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Data and other attributes defined here:
|
Data and other attributes defined here:
|
||||||
NO_MEANING = 'eggs'
|
NO_MEANING = 'eggs'
|
||||||
__annotations__ = {'NO_MEANING': <class 'str'>}
|
|
||||||
|
|
||||||
|
|
||||||
class C(builtins.object)
|
class C(builtins.object)
|
||||||
|
|
|
@ -105,7 +105,7 @@ class TestSimpleInteract(unittest.TestCase):
|
||||||
|
|
||||||
def test_no_active_future(self):
|
def test_no_active_future(self):
|
||||||
console = InteractiveColoredConsole()
|
console = InteractiveColoredConsole()
|
||||||
source = "x: int = 1; print(__annotations__)"
|
source = "x: int = 1; print(__annotate__(1))"
|
||||||
f = io.StringIO()
|
f = io.StringIO()
|
||||||
with contextlib.redirect_stdout(f):
|
with contextlib.redirect_stdout(f):
|
||||||
result = console.runsource(source)
|
result = console.runsource(source)
|
||||||
|
|
|
@ -205,12 +205,14 @@ class SymtableTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_annotated(self):
|
def test_annotated(self):
|
||||||
st1 = symtable.symtable('def f():\n x: int\n', 'test', 'exec')
|
st1 = symtable.symtable('def f():\n x: int\n', 'test', 'exec')
|
||||||
st2 = st1.get_children()[0]
|
st2 = st1.get_children()[1]
|
||||||
|
self.assertEqual(st2.get_type(), "function")
|
||||||
self.assertTrue(st2.lookup('x').is_local())
|
self.assertTrue(st2.lookup('x').is_local())
|
||||||
self.assertTrue(st2.lookup('x').is_annotated())
|
self.assertTrue(st2.lookup('x').is_annotated())
|
||||||
self.assertFalse(st2.lookup('x').is_global())
|
self.assertFalse(st2.lookup('x').is_global())
|
||||||
st3 = symtable.symtable('def f():\n x = 1\n', 'test', 'exec')
|
st3 = symtable.symtable('def f():\n x = 1\n', 'test', 'exec')
|
||||||
st4 = st3.get_children()[0]
|
st4 = st3.get_children()[1]
|
||||||
|
self.assertEqual(st4.get_type(), "function")
|
||||||
self.assertTrue(st4.lookup('x').is_local())
|
self.assertTrue(st4.lookup('x').is_local())
|
||||||
self.assertFalse(st4.lookup('x').is_annotated())
|
self.assertFalse(st4.lookup('x').is_annotated())
|
||||||
|
|
||||||
|
|
|
@ -622,6 +622,7 @@ class TracebackErrorLocationCaretTestBase:
|
||||||
def f_with_type():
|
def f_with_type():
|
||||||
def foo(a: THIS_DOES_NOT_EXIST ) -> int:
|
def foo(a: THIS_DOES_NOT_EXIST ) -> int:
|
||||||
return 0
|
return 0
|
||||||
|
foo.__annotations__
|
||||||
|
|
||||||
lineno_f = f_with_type.__code__.co_firstlineno
|
lineno_f = f_with_type.__code__.co_firstlineno
|
||||||
expected_f = (
|
expected_f = (
|
||||||
|
@ -629,7 +630,9 @@ class TracebackErrorLocationCaretTestBase:
|
||||||
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
|
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
|
||||||
' callable()\n'
|
' callable()\n'
|
||||||
' ~~~~~~~~^^\n'
|
' ~~~~~~~~^^\n'
|
||||||
f' File "{__file__}", line {lineno_f+1}, in f_with_type\n'
|
f' File "{__file__}", line {lineno_f+3}, in f_with_type\n'
|
||||||
|
' foo.__annotations__\n'
|
||||||
|
f' File "{__file__}", line {lineno_f+1}, in __annotate__\n'
|
||||||
' def foo(a: THIS_DOES_NOT_EXIST ) -> int:\n'
|
' def foo(a: THIS_DOES_NOT_EXIST ) -> int:\n'
|
||||||
' ^^^^^^^^^^^^^^^^^^^\n'
|
' ^^^^^^^^^^^^^^^^^^^\n'
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import textwrap
|
import textwrap
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import run_code
|
from test.support import run_code, check_syntax_error
|
||||||
|
|
||||||
|
VALUE = 1
|
||||||
|
FORWARDREF = 2
|
||||||
|
SOURCE = 3
|
||||||
|
|
||||||
|
|
||||||
class TypeAnnotationTests(unittest.TestCase):
|
class TypeAnnotationTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -49,6 +54,7 @@ class TypeAnnotationTests(unittest.TestCase):
|
||||||
class C:
|
class C:
|
||||||
a:int=3
|
a:int=3
|
||||||
b:str=4
|
b:str=4
|
||||||
|
self.assertEqual(C.__annotations__, {"a": int, "b": str})
|
||||||
self.assertTrue("__annotations__" in C.__dict__)
|
self.assertTrue("__annotations__" in C.__dict__)
|
||||||
del C.__annotations__
|
del C.__annotations__
|
||||||
self.assertFalse("__annotations__" in C.__dict__)
|
self.assertFalse("__annotations__" in C.__dict__)
|
||||||
|
@ -106,6 +112,13 @@ class TypeAnnotationTests(unittest.TestCase):
|
||||||
self.assertEqual(D.__annotations__, {})
|
self.assertEqual(D.__annotations__, {})
|
||||||
|
|
||||||
|
|
||||||
|
def build_module(code: str, name: str = "top") -> types.ModuleType:
|
||||||
|
ns = run_code(code)
|
||||||
|
mod = types.ModuleType(name)
|
||||||
|
mod.__dict__.update(ns)
|
||||||
|
return mod
|
||||||
|
|
||||||
|
|
||||||
class TestSetupAnnotations(unittest.TestCase):
|
class TestSetupAnnotations(unittest.TestCase):
|
||||||
def check(self, code: str):
|
def check(self, code: str):
|
||||||
code = textwrap.dedent(code)
|
code = textwrap.dedent(code)
|
||||||
|
@ -113,11 +126,10 @@ class TestSetupAnnotations(unittest.TestCase):
|
||||||
with self.subTest(scope=scope):
|
with self.subTest(scope=scope):
|
||||||
if scope == "class":
|
if scope == "class":
|
||||||
code = f"class C:\n{textwrap.indent(code, ' ')}"
|
code = f"class C:\n{textwrap.indent(code, ' ')}"
|
||||||
ns = run_code(code)
|
ns = run_code(code)
|
||||||
if scope == "class":
|
|
||||||
annotations = ns["C"].__annotations__
|
annotations = ns["C"].__annotations__
|
||||||
else:
|
else:
|
||||||
annotations = ns["__annotations__"]
|
annotations = build_module(code).__annotations__
|
||||||
self.assertEqual(annotations, {"x": int})
|
self.assertEqual(annotations, {"x": int})
|
||||||
|
|
||||||
def test_top_level(self):
|
def test_top_level(self):
|
||||||
|
@ -256,3 +268,146 @@ class AnnotateTests(unittest.TestCase):
|
||||||
# Setting f.__annotations__ also clears __annotate__
|
# Setting f.__annotations__ also clears __annotate__
|
||||||
f.__annotations__ = {"z": 43}
|
f.__annotations__ = {"z": 43}
|
||||||
self.assertIs(f.__annotate__, None)
|
self.assertIs(f.__annotate__, None)
|
||||||
|
|
||||||
|
|
||||||
|
class DeferredEvaluationTests(unittest.TestCase):
|
||||||
|
def test_function(self):
|
||||||
|
def func(x: undefined, /, y: undefined, *args: undefined, z: undefined, **kwargs: undefined) -> undefined:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(NameError):
|
||||||
|
func.__annotations__
|
||||||
|
|
||||||
|
undefined = 1
|
||||||
|
self.assertEqual(func.__annotations__, {
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"args": 1,
|
||||||
|
"z": 1,
|
||||||
|
"kwargs": 1,
|
||||||
|
"return": 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_async_function(self):
|
||||||
|
async def func(x: undefined, /, y: undefined, *args: undefined, z: undefined, **kwargs: undefined) -> undefined:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(NameError):
|
||||||
|
func.__annotations__
|
||||||
|
|
||||||
|
undefined = 1
|
||||||
|
self.assertEqual(func.__annotations__, {
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"args": 1,
|
||||||
|
"z": 1,
|
||||||
|
"kwargs": 1,
|
||||||
|
"return": 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_class(self):
|
||||||
|
class X:
|
||||||
|
a: undefined
|
||||||
|
|
||||||
|
with self.assertRaises(NameError):
|
||||||
|
X.__annotations__
|
||||||
|
|
||||||
|
undefined = 1
|
||||||
|
self.assertEqual(X.__annotations__, {"a": 1})
|
||||||
|
|
||||||
|
def test_module(self):
|
||||||
|
ns = run_code("x: undefined = 1")
|
||||||
|
anno = ns["__annotate__"]
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
anno(2)
|
||||||
|
|
||||||
|
with self.assertRaises(NameError):
|
||||||
|
anno(1)
|
||||||
|
|
||||||
|
ns["undefined"] = 1
|
||||||
|
self.assertEqual(anno(1), {"x": 1})
|
||||||
|
|
||||||
|
def test_class_scoping(self):
|
||||||
|
class Outer:
|
||||||
|
def meth(self, x: Nested): ...
|
||||||
|
x: Nested
|
||||||
|
class Nested: ...
|
||||||
|
|
||||||
|
self.assertEqual(Outer.meth.__annotations__, {"x": Outer.Nested})
|
||||||
|
self.assertEqual(Outer.__annotations__, {"x": Outer.Nested})
|
||||||
|
|
||||||
|
def test_no_exotic_expressions(self):
|
||||||
|
check_syntax_error(self, "def func(x: (yield)): ...", "yield expression cannot be used within an annotation")
|
||||||
|
check_syntax_error(self, "def func(x: (yield from x)): ...", "yield expression cannot be used within an annotation")
|
||||||
|
check_syntax_error(self, "def func(x: (y := 3)): ...", "named expression cannot be used within an annotation")
|
||||||
|
check_syntax_error(self, "def func(x: (await 42)): ...", "await expression cannot be used within an annotation")
|
||||||
|
|
||||||
|
def test_no_exotic_expressions_in_unevaluated_annotations(self):
|
||||||
|
preludes = [
|
||||||
|
"",
|
||||||
|
"class X: ",
|
||||||
|
"def f(): ",
|
||||||
|
"async def f(): ",
|
||||||
|
]
|
||||||
|
for prelude in preludes:
|
||||||
|
with self.subTest(prelude=prelude):
|
||||||
|
check_syntax_error(self, prelude + "(x): (yield)", "yield expression cannot be used within an annotation")
|
||||||
|
check_syntax_error(self, prelude + "(x): (yield from x)", "yield expression cannot be used within an annotation")
|
||||||
|
check_syntax_error(self, prelude + "(x): (y := 3)", "named expression cannot be used within an annotation")
|
||||||
|
check_syntax_error(self, prelude + "(x): (await 42)", "await expression cannot be used within an annotation")
|
||||||
|
|
||||||
|
def test_ignore_non_simple_annotations(self):
|
||||||
|
ns = run_code("class X: (y): int")
|
||||||
|
self.assertEqual(ns["X"].__annotations__, {})
|
||||||
|
ns = run_code("class X: int.b: int")
|
||||||
|
self.assertEqual(ns["X"].__annotations__, {})
|
||||||
|
ns = run_code("class X: int[str]: int")
|
||||||
|
self.assertEqual(ns["X"].__annotations__, {})
|
||||||
|
|
||||||
|
def test_generated_annotate(self):
|
||||||
|
def func(x: int):
|
||||||
|
pass
|
||||||
|
class X:
|
||||||
|
x: int
|
||||||
|
mod = build_module("x: int")
|
||||||
|
for obj in (func, X, mod):
|
||||||
|
with self.subTest(obj=obj):
|
||||||
|
annotate = obj.__annotate__
|
||||||
|
self.assertIsInstance(annotate, types.FunctionType)
|
||||||
|
self.assertEqual(annotate.__name__, "__annotate__")
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
annotate(FORWARDREF)
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
annotate(SOURCE)
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
annotate(None)
|
||||||
|
self.assertEqual(annotate(VALUE), {"x": int})
|
||||||
|
|
||||||
|
def test_comprehension_in_annotation(self):
|
||||||
|
# This crashed in an earlier version of the code
|
||||||
|
ns = run_code("x: [y for y in range(10)]")
|
||||||
|
self.assertEqual(ns["__annotate__"](1), {"x": list(range(10))})
|
||||||
|
|
||||||
|
def test_future_annotations(self):
|
||||||
|
code = """
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
def f(x: int) -> int: pass
|
||||||
|
"""
|
||||||
|
ns = run_code(code)
|
||||||
|
f = ns["f"]
|
||||||
|
self.assertIsInstance(f.__annotate__, types.FunctionType)
|
||||||
|
annos = {"x": "int", "return": "int"}
|
||||||
|
self.assertEqual(f.__annotate__(VALUE), annos)
|
||||||
|
self.assertEqual(f.__annotations__, annos)
|
||||||
|
|
||||||
|
def test_name_clash_with_format(self):
|
||||||
|
# this test would fail if __annotate__'s parameter was called "format"
|
||||||
|
code = """
|
||||||
|
class format: pass
|
||||||
|
|
||||||
|
def f(x: format): pass
|
||||||
|
"""
|
||||||
|
ns = run_code(code)
|
||||||
|
f = ns["f"]
|
||||||
|
self.assertEqual(f.__annotations__, {"x": ns["format"]})
|
||||||
|
|
|
@ -6634,7 +6634,7 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
gth(None)
|
gth(None)
|
||||||
|
|
||||||
def test_get_type_hints_modules(self):
|
def test_get_type_hints_modules(self):
|
||||||
ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str, 'u': int | float}
|
ann_module_type_hints = {'f': Tuple[int, int], 'x': int, 'y': str, 'u': int | float}
|
||||||
self.assertEqual(gth(ann_module), ann_module_type_hints)
|
self.assertEqual(gth(ann_module), ann_module_type_hints)
|
||||||
self.assertEqual(gth(ann_module2), {})
|
self.assertEqual(gth(ann_module2), {})
|
||||||
self.assertEqual(gth(ann_module3), {})
|
self.assertEqual(gth(ann_module3), {})
|
||||||
|
@ -6652,7 +6652,7 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
self.assertEqual(gth(ann_module.C), # gth will find the right globalns
|
self.assertEqual(gth(ann_module.C), # gth will find the right globalns
|
||||||
{'y': Optional[ann_module.C]})
|
{'y': Optional[ann_module.C]})
|
||||||
self.assertIsInstance(gth(ann_module.j_class), dict)
|
self.assertIsInstance(gth(ann_module.j_class), dict)
|
||||||
self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type})
|
self.assertEqual(gth(ann_module.M), {'o': type})
|
||||||
self.assertEqual(gth(ann_module.D),
|
self.assertEqual(gth(ann_module.D),
|
||||||
{'j': str, 'k': str, 'y': Optional[ann_module.C]})
|
{'j': str, 'k': str, 'y': Optional[ann_module.C]})
|
||||||
self.assertEqual(gth(ann_module.Y), {'z': int})
|
self.assertEqual(gth(ann_module.Y), {'z': int})
|
||||||
|
|
|
@ -8,8 +8,6 @@ Empty lines above are for good reason (testing for correct line numbers)
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
__annotations__[1] = 2
|
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
|
|
||||||
x = 5; y: Optional['C'] = None
|
x = 5; y: Optional['C'] = None
|
||||||
|
@ -18,8 +16,6 @@ from typing import Tuple
|
||||||
x: int = 5; y: str = x; f: Tuple[int, int]
|
x: int = 5; y: str = x; f: Tuple[int, int]
|
||||||
|
|
||||||
class M(type):
|
class M(type):
|
||||||
|
|
||||||
__annotations__['123'] = 123
|
|
||||||
o: type = object
|
o: type = object
|
||||||
|
|
||||||
(pars): bool = True
|
(pars): bool = True
|
||||||
|
|
|
@ -2412,7 +2412,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
|
||||||
base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {})
|
base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {})
|
||||||
else:
|
else:
|
||||||
base_globals = globalns
|
base_globals = globalns
|
||||||
ann = base.__dict__.get('__annotations__', {})
|
ann = getattr(base, '__annotations__', {})
|
||||||
if isinstance(ann, types.GetSetDescriptorType):
|
if isinstance(ann, types.GetSetDescriptorType):
|
||||||
ann = {}
|
ann = {}
|
||||||
base_locals = dict(vars(base)) if localns is None else localns
|
base_locals = dict(vars(base)) if localns is None else localns
|
||||||
|
@ -2970,7 +2970,12 @@ class NamedTupleMeta(type):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
'can only inherit from a NamedTuple type and Generic')
|
'can only inherit from a NamedTuple type and Generic')
|
||||||
bases = tuple(tuple if base is _NamedTuple else base for base in bases)
|
bases = tuple(tuple if base is _NamedTuple else base for base in bases)
|
||||||
types = ns.get('__annotations__', {})
|
if "__annotations__" in ns:
|
||||||
|
types = ns["__annotations__"]
|
||||||
|
elif "__annotate__" in ns:
|
||||||
|
types = ns["__annotate__"](1) # VALUE
|
||||||
|
else:
|
||||||
|
types = {}
|
||||||
default_names = []
|
default_names = []
|
||||||
for field_name in types:
|
for field_name in types:
|
||||||
if field_name in ns:
|
if field_name in ns:
|
||||||
|
@ -3131,7 +3136,12 @@ class _TypedDictMeta(type):
|
||||||
tp_dict.__orig_bases__ = bases
|
tp_dict.__orig_bases__ = bases
|
||||||
|
|
||||||
annotations = {}
|
annotations = {}
|
||||||
own_annotations = ns.get('__annotations__', {})
|
if "__annotations__" in ns:
|
||||||
|
own_annotations = ns["__annotations__"]
|
||||||
|
elif "__annotate__" in ns:
|
||||||
|
own_annotations = ns["__annotate__"](1) # VALUE
|
||||||
|
else:
|
||||||
|
own_annotations = {}
|
||||||
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
|
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
|
||||||
own_annotations = {
|
own_annotations = {
|
||||||
n: _type_check(tp, msg, module=tp_dict.__module__)
|
n: _type_check(tp, msg, module=tp_dict.__module__)
|
||||||
|
@ -3143,7 +3153,12 @@ class _TypedDictMeta(type):
|
||||||
mutable_keys = set()
|
mutable_keys = set()
|
||||||
|
|
||||||
for base in bases:
|
for base in bases:
|
||||||
annotations.update(base.__dict__.get('__annotations__', {}))
|
# TODO: Avoid eagerly evaluating annotations in VALUE format.
|
||||||
|
# Instead, evaluate in FORWARDREF format to figure out which
|
||||||
|
# keys have Required/NotRequired/ReadOnly qualifiers, and create
|
||||||
|
# a new __annotate__ function for the resulting TypedDict that
|
||||||
|
# combines the annotations from this class and its parents.
|
||||||
|
annotations.update(base.__annotations__)
|
||||||
|
|
||||||
base_required = base.__dict__.get('__required_keys__', set())
|
base_required = base.__dict__.get('__required_keys__', set())
|
||||||
required_keys |= base_required
|
required_keys |= base_required
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Evaluation of annotations is now deferred. See :pep:`649` for details.
|
|
@ -3975,6 +3975,11 @@ dummy_func(
|
||||||
assert(func_obj->func_defaults == NULL);
|
assert(func_obj->func_defaults == NULL);
|
||||||
func_obj->func_defaults = attr;
|
func_obj->func_defaults = attr;
|
||||||
break;
|
break;
|
||||||
|
case MAKE_FUNCTION_ANNOTATE:
|
||||||
|
assert(PyCallable_Check(attr));
|
||||||
|
assert(func_obj->func_annotate == NULL);
|
||||||
|
func_obj->func_annotate = attr;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
359
Python/compile.c
359
Python/compile.c
|
@ -132,7 +132,7 @@ enum {
|
||||||
COMPILER_SCOPE_ASYNC_FUNCTION,
|
COMPILER_SCOPE_ASYNC_FUNCTION,
|
||||||
COMPILER_SCOPE_LAMBDA,
|
COMPILER_SCOPE_LAMBDA,
|
||||||
COMPILER_SCOPE_COMPREHENSION,
|
COMPILER_SCOPE_COMPREHENSION,
|
||||||
COMPILER_SCOPE_TYPEPARAMS,
|
COMPILER_SCOPE_ANNOTATIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,6 +142,15 @@ typedef _PyInstructionSequence instr_sequence;
|
||||||
#define INITIAL_INSTR_SEQUENCE_SIZE 100
|
#define INITIAL_INSTR_SEQUENCE_SIZE 100
|
||||||
#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10
|
#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10
|
||||||
|
|
||||||
|
static const int compare_masks[] = {
|
||||||
|
[Py_LT] = COMPARISON_LESS_THAN,
|
||||||
|
[Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS,
|
||||||
|
[Py_EQ] = COMPARISON_EQUALS,
|
||||||
|
[Py_NE] = COMPARISON_NOT_EQUALS,
|
||||||
|
[Py_GT] = COMPARISON_GREATER_THAN,
|
||||||
|
[Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resize the array if index is out of range.
|
* Resize the array if index is out of range.
|
||||||
*
|
*
|
||||||
|
@ -208,6 +217,7 @@ struct compiler_unit {
|
||||||
|
|
||||||
PyObject *u_private; /* for private name mangling */
|
PyObject *u_private; /* for private name mangling */
|
||||||
PyObject *u_static_attributes; /* for class: attributes accessed via self.X */
|
PyObject *u_static_attributes; /* for class: attributes accessed via self.X */
|
||||||
|
PyObject *u_deferred_annotations; /* AnnAssign nodes deferred to the end of compilation */
|
||||||
|
|
||||||
instr_sequence *u_instr_sequence; /* codegen output */
|
instr_sequence *u_instr_sequence; /* codegen output */
|
||||||
|
|
||||||
|
@ -330,6 +340,8 @@ static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *);
|
||||||
static int compiler_match(struct compiler *, stmt_ty);
|
static int compiler_match(struct compiler *, stmt_ty);
|
||||||
static int compiler_pattern_subpattern(struct compiler *,
|
static int compiler_pattern_subpattern(struct compiler *,
|
||||||
pattern_ty, pattern_context *);
|
pattern_ty, pattern_context *);
|
||||||
|
static int compiler_make_closure(struct compiler *c, location loc,
|
||||||
|
PyCodeObject *co, Py_ssize_t flags);
|
||||||
|
|
||||||
static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
|
static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
|
||||||
|
|
||||||
|
@ -545,6 +557,7 @@ compiler_unit_free(struct compiler_unit *u)
|
||||||
Py_CLEAR(u->u_metadata.u_fasthidden);
|
Py_CLEAR(u->u_metadata.u_fasthidden);
|
||||||
Py_CLEAR(u->u_private);
|
Py_CLEAR(u->u_private);
|
||||||
Py_CLEAR(u->u_static_attributes);
|
Py_CLEAR(u->u_static_attributes);
|
||||||
|
Py_CLEAR(u->u_deferred_annotations);
|
||||||
PyMem_Free(u);
|
PyMem_Free(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,8 +595,8 @@ compiler_set_qualname(struct compiler *c)
|
||||||
capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
|
capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
|
||||||
parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME);
|
parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME);
|
||||||
assert(parent);
|
assert(parent);
|
||||||
if (parent->u_scope_type == COMPILER_SCOPE_TYPEPARAMS) {
|
if (parent->u_scope_type == COMPILER_SCOPE_ANNOTATIONS) {
|
||||||
/* The parent is a type parameter scope, so we need to
|
/* The parent is an annotation scope, so we need to
|
||||||
look at the grandparent. */
|
look at the grandparent. */
|
||||||
if (stack_size == 2) {
|
if (stack_size == 2) {
|
||||||
// If we're immediately within the module, we can skip
|
// If we're immediately within the module, we can skip
|
||||||
|
@ -1128,6 +1141,7 @@ compiler_enter_scope(struct compiler *c, identifier name,
|
||||||
}
|
}
|
||||||
|
|
||||||
u->u_private = NULL;
|
u->u_private = NULL;
|
||||||
|
u->u_deferred_annotations = NULL;
|
||||||
if (scope_type == COMPILER_SCOPE_CLASS) {
|
if (scope_type == COMPILER_SCOPE_CLASS) {
|
||||||
u->u_static_attributes = PySet_New(0);
|
u->u_static_attributes = PySet_New(0);
|
||||||
if (!u->u_static_attributes) {
|
if (!u->u_static_attributes) {
|
||||||
|
@ -1209,85 +1223,6 @@ compiler_exit_scope(struct compiler *c)
|
||||||
PyErr_SetRaisedException(exc);
|
PyErr_SetRaisedException(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search if variable annotations are present statically in a block. */
|
|
||||||
|
|
||||||
static bool
|
|
||||||
find_ann(asdl_stmt_seq *stmts)
|
|
||||||
{
|
|
||||||
int i, j, res = 0;
|
|
||||||
stmt_ty st;
|
|
||||||
|
|
||||||
for (i = 0; i < asdl_seq_LEN(stmts); i++) {
|
|
||||||
st = (stmt_ty)asdl_seq_GET(stmts, i);
|
|
||||||
switch (st->kind) {
|
|
||||||
case AnnAssign_kind:
|
|
||||||
return true;
|
|
||||||
case For_kind:
|
|
||||||
res = find_ann(st->v.For.body) ||
|
|
||||||
find_ann(st->v.For.orelse);
|
|
||||||
break;
|
|
||||||
case AsyncFor_kind:
|
|
||||||
res = find_ann(st->v.AsyncFor.body) ||
|
|
||||||
find_ann(st->v.AsyncFor.orelse);
|
|
||||||
break;
|
|
||||||
case While_kind:
|
|
||||||
res = find_ann(st->v.While.body) ||
|
|
||||||
find_ann(st->v.While.orelse);
|
|
||||||
break;
|
|
||||||
case If_kind:
|
|
||||||
res = find_ann(st->v.If.body) ||
|
|
||||||
find_ann(st->v.If.orelse);
|
|
||||||
break;
|
|
||||||
case With_kind:
|
|
||||||
res = find_ann(st->v.With.body);
|
|
||||||
break;
|
|
||||||
case AsyncWith_kind:
|
|
||||||
res = find_ann(st->v.AsyncWith.body);
|
|
||||||
break;
|
|
||||||
case Try_kind:
|
|
||||||
for (j = 0; j < asdl_seq_LEN(st->v.Try.handlers); j++) {
|
|
||||||
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
|
|
||||||
st->v.Try.handlers, j);
|
|
||||||
if (find_ann(handler->v.ExceptHandler.body)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = find_ann(st->v.Try.body) ||
|
|
||||||
find_ann(st->v.Try.finalbody) ||
|
|
||||||
find_ann(st->v.Try.orelse);
|
|
||||||
break;
|
|
||||||
case TryStar_kind:
|
|
||||||
for (j = 0; j < asdl_seq_LEN(st->v.TryStar.handlers); j++) {
|
|
||||||
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
|
|
||||||
st->v.TryStar.handlers, j);
|
|
||||||
if (find_ann(handler->v.ExceptHandler.body)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = find_ann(st->v.TryStar.body) ||
|
|
||||||
find_ann(st->v.TryStar.finalbody) ||
|
|
||||||
find_ann(st->v.TryStar.orelse);
|
|
||||||
break;
|
|
||||||
case Match_kind:
|
|
||||||
for (j = 0; j < asdl_seq_LEN(st->v.Match.cases); j++) {
|
|
||||||
match_case_ty match_case = (match_case_ty)asdl_seq_GET(
|
|
||||||
st->v.Match.cases, j);
|
|
||||||
if (find_ann(match_case->body)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (res) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Frame block handling functions
|
* Frame block handling functions
|
||||||
*/
|
*/
|
||||||
|
@ -1502,6 +1437,47 @@ compiler_unwind_fblock_stack(struct compiler *c, location *ploc,
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compiler_setup_annotations_scope(struct compiler *c, location loc,
|
||||||
|
void *key, PyObject *name)
|
||||||
|
{
|
||||||
|
if (compiler_enter_scope(c, name, COMPILER_SCOPE_ANNOTATIONS,
|
||||||
|
key, loc.lineno) == -1) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
c->u->u_metadata.u_posonlyargcount = 1;
|
||||||
|
// if .format != 1: raise NotImplementedError
|
||||||
|
_Py_DECLARE_STR(format, ".format");
|
||||||
|
ADDOP_I(c, loc, LOAD_FAST, 0);
|
||||||
|
ADDOP_LOAD_CONST(c, loc, _PyLong_GetOne());
|
||||||
|
ADDOP_I(c, loc, COMPARE_OP, (Py_NE << 5) | compare_masks[Py_NE]);
|
||||||
|
NEW_JUMP_TARGET_LABEL(c, body);
|
||||||
|
ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, body);
|
||||||
|
ADDOP_I(c, loc, LOAD_COMMON_CONSTANT, CONSTANT_NOTIMPLEMENTEDERROR);
|
||||||
|
ADDOP_I(c, loc, RAISE_VARARGS, 1);
|
||||||
|
USE_LABEL(c, body);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compiler_leave_annotations_scope(struct compiler *c, location loc,
|
||||||
|
Py_ssize_t annotations_len)
|
||||||
|
{
|
||||||
|
ADDOP_I(c, loc, BUILD_MAP, annotations_len);
|
||||||
|
ADDOP_IN_SCOPE(c, loc, RETURN_VALUE);
|
||||||
|
PyCodeObject *co = optimize_and_assemble(c, 1);
|
||||||
|
compiler_exit_scope(c);
|
||||||
|
if (co == NULL) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
if (compiler_make_closure(c, loc, co, 0) < 0) {
|
||||||
|
Py_DECREF(co);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
Py_DECREF(co);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compile a sequence of statements, checking for a docstring
|
/* Compile a sequence of statements, checking for a docstring
|
||||||
and for annotations. */
|
and for annotations. */
|
||||||
|
|
||||||
|
@ -1517,34 +1493,79 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts)
|
||||||
stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0);
|
stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0);
|
||||||
loc = LOC(st);
|
loc = LOC(st);
|
||||||
}
|
}
|
||||||
/* Every annotated class and module should have __annotations__. */
|
/* If from __future__ import annotations is active,
|
||||||
if (find_ann(stmts)) {
|
* every annotated class and module should have __annotations__.
|
||||||
|
* Else __annotate__ is created when necessary. */
|
||||||
|
if ((c->c_future.ff_features & CO_FUTURE_ANNOTATIONS) && c->u->u_ste->ste_annotations_used) {
|
||||||
ADDOP(c, loc, SETUP_ANNOTATIONS);
|
ADDOP(c, loc, SETUP_ANNOTATIONS);
|
||||||
}
|
}
|
||||||
if (!asdl_seq_LEN(stmts)) {
|
if (!asdl_seq_LEN(stmts)) {
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
Py_ssize_t first_instr = 0;
|
Py_ssize_t first_instr = 0;
|
||||||
PyObject *docstring = _PyAST_GetDocString(stmts);
|
if (!c->c_interactive) {
|
||||||
if (docstring) {
|
PyObject *docstring = _PyAST_GetDocString(stmts);
|
||||||
first_instr = 1;
|
if (docstring) {
|
||||||
/* if not -OO mode, set docstring */
|
first_instr = 1;
|
||||||
if (c->c_optimize < 2) {
|
/* if not -OO mode, set docstring */
|
||||||
PyObject *cleandoc = _PyCompile_CleanDoc(docstring);
|
if (c->c_optimize < 2) {
|
||||||
if (cleandoc == NULL) {
|
PyObject *cleandoc = _PyCompile_CleanDoc(docstring);
|
||||||
return ERROR;
|
if (cleandoc == NULL) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0);
|
||||||
|
assert(st->kind == Expr_kind);
|
||||||
|
location loc = LOC(st->v.Expr.value);
|
||||||
|
ADDOP_LOAD_CONST(c, loc, cleandoc);
|
||||||
|
Py_DECREF(cleandoc);
|
||||||
|
RETURN_IF_ERROR(compiler_nameop(c, NO_LOCATION, &_Py_ID(__doc__), Store));
|
||||||
}
|
}
|
||||||
stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0);
|
|
||||||
assert(st->kind == Expr_kind);
|
|
||||||
location loc = LOC(st->v.Expr.value);
|
|
||||||
ADDOP_LOAD_CONST(c, loc, cleandoc);
|
|
||||||
Py_DECREF(cleandoc);
|
|
||||||
RETURN_IF_ERROR(compiler_nameop(c, NO_LOCATION, &_Py_ID(__doc__), Store));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Py_ssize_t i = first_instr; i < asdl_seq_LEN(stmts); i++) {
|
for (Py_ssize_t i = first_instr; i < asdl_seq_LEN(stmts); i++) {
|
||||||
VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i));
|
VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i));
|
||||||
}
|
}
|
||||||
|
// If there are annotations and the future import is not on, we
|
||||||
|
// collect the annotations in a separate pass and generate an
|
||||||
|
// __annotate__ function. See PEP 649.
|
||||||
|
if (!(c->c_future.ff_features & CO_FUTURE_ANNOTATIONS) &&
|
||||||
|
c->u->u_deferred_annotations != NULL) {
|
||||||
|
|
||||||
|
// It's possible that ste_annotations_block is set but
|
||||||
|
// u_deferred_annotations is not, because the former is still
|
||||||
|
// set if there are only non-simple annotations (i.e., annotations
|
||||||
|
// for attributes, subscripts, or parenthesized names). However, the
|
||||||
|
// reverse should not be possible.
|
||||||
|
assert(c->u->u_ste->ste_annotation_block != NULL);
|
||||||
|
PyObject *deferred_anno = Py_NewRef(c->u->u_deferred_annotations);
|
||||||
|
void *key = (void *)((uintptr_t)c->u->u_ste->ste_id + 1);
|
||||||
|
if (compiler_setup_annotations_scope(c, loc, key,
|
||||||
|
c->u->u_ste->ste_annotation_block->ste_name) == -1) {
|
||||||
|
Py_DECREF(deferred_anno);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
Py_ssize_t annotations_len = PyList_Size(deferred_anno);
|
||||||
|
for (Py_ssize_t i = 0; i < annotations_len; i++) {
|
||||||
|
PyObject *ptr = PyList_GET_ITEM(deferred_anno, i);
|
||||||
|
stmt_ty st = (stmt_ty)PyLong_AsVoidPtr(ptr);
|
||||||
|
if (st == NULL) {
|
||||||
|
compiler_exit_scope(c);
|
||||||
|
Py_DECREF(deferred_anno);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
PyObject *mangled = _Py_Mangle(c->u->u_private, st->v.AnnAssign.target->v.Name.id);
|
||||||
|
ADDOP_LOAD_CONST_NEW(c, LOC(st), mangled);
|
||||||
|
VISIT(c, expr, st->v.AnnAssign.annotation);
|
||||||
|
}
|
||||||
|
Py_DECREF(deferred_anno);
|
||||||
|
|
||||||
|
RETURN_IF_ERROR(
|
||||||
|
compiler_leave_annotations_scope(c, loc, annotations_len)
|
||||||
|
);
|
||||||
|
RETURN_IF_ERROR(
|
||||||
|
compiler_nameop(c, loc, &_Py_ID(__annotate__), Store)
|
||||||
|
);
|
||||||
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1559,11 +1580,10 @@ compiler_codegen(struct compiler *c, mod_ty mod)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Interactive_kind:
|
case Interactive_kind:
|
||||||
if (find_ann(mod->v.Interactive.body)) {
|
|
||||||
ADDOP(c, loc, SETUP_ANNOTATIONS);
|
|
||||||
}
|
|
||||||
c->c_interactive = 1;
|
c->c_interactive = 1;
|
||||||
VISIT_SEQ(c, stmt, mod->v.Interactive.body);
|
if (compiler_body(c, loc, mod->v.Interactive.body) < 0) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Expression_kind:
|
case Expression_kind:
|
||||||
VISIT(c, expr, mod->v.Expression.body);
|
VISIT(c, expr, mod->v.Expression.body);
|
||||||
|
@ -1702,6 +1722,9 @@ compiler_make_closure(struct compiler *c, location loc,
|
||||||
if (flags & MAKE_FUNCTION_ANNOTATIONS) {
|
if (flags & MAKE_FUNCTION_ANNOTATIONS) {
|
||||||
ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_ANNOTATIONS);
|
ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_ANNOTATIONS);
|
||||||
}
|
}
|
||||||
|
if (flags & MAKE_FUNCTION_ANNOTATE) {
|
||||||
|
ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_ANNOTATE);
|
||||||
|
}
|
||||||
if (flags & MAKE_FUNCTION_KWDEFAULTS) {
|
if (flags & MAKE_FUNCTION_KWDEFAULTS) {
|
||||||
ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_KWDEFAULTS);
|
ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_KWDEFAULTS);
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1856,7 @@ compiler_visit_argannotation(struct compiler *c, identifier id,
|
||||||
VISIT(c, expr, annotation);
|
VISIT(c, expr, annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*annotations_len += 2;
|
*annotations_len += 1;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1856,43 +1879,76 @@ compiler_visit_argannotations(struct compiler *c, asdl_arg_seq* args,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compiler_visit_annotations(struct compiler *c, location loc,
|
compiler_visit_annotations_in_scope(struct compiler *c, location loc,
|
||||||
arguments_ty args, expr_ty returns)
|
arguments_ty args, expr_ty returns,
|
||||||
|
Py_ssize_t *annotations_len)
|
||||||
{
|
{
|
||||||
/* Push arg annotation names and values.
|
RETURN_IF_ERROR(
|
||||||
The expressions are evaluated out-of-order wrt the source code.
|
compiler_visit_argannotations(c, args->args, annotations_len, loc));
|
||||||
|
|
||||||
Return -1 on error, 0 if no annotations pushed, 1 if a annotations is pushed.
|
|
||||||
*/
|
|
||||||
Py_ssize_t annotations_len = 0;
|
|
||||||
|
|
||||||
RETURN_IF_ERROR(
|
RETURN_IF_ERROR(
|
||||||
compiler_visit_argannotations(c, args->args, &annotations_len, loc));
|
compiler_visit_argannotations(c, args->posonlyargs, annotations_len, loc));
|
||||||
|
|
||||||
RETURN_IF_ERROR(
|
|
||||||
compiler_visit_argannotations(c, args->posonlyargs, &annotations_len, loc));
|
|
||||||
|
|
||||||
if (args->vararg && args->vararg->annotation) {
|
if (args->vararg && args->vararg->annotation) {
|
||||||
RETURN_IF_ERROR(
|
RETURN_IF_ERROR(
|
||||||
compiler_visit_argannotation(c, args->vararg->arg,
|
compiler_visit_argannotation(c, args->vararg->arg,
|
||||||
args->vararg->annotation, &annotations_len, loc));
|
args->vararg->annotation, annotations_len, loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_IF_ERROR(
|
RETURN_IF_ERROR(
|
||||||
compiler_visit_argannotations(c, args->kwonlyargs, &annotations_len, loc));
|
compiler_visit_argannotations(c, args->kwonlyargs, annotations_len, loc));
|
||||||
|
|
||||||
if (args->kwarg && args->kwarg->annotation) {
|
if (args->kwarg && args->kwarg->annotation) {
|
||||||
RETURN_IF_ERROR(
|
RETURN_IF_ERROR(
|
||||||
compiler_visit_argannotation(c, args->kwarg->arg,
|
compiler_visit_argannotation(c, args->kwarg->arg,
|
||||||
args->kwarg->annotation, &annotations_len, loc));
|
args->kwarg->annotation, annotations_len, loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_IF_ERROR(
|
RETURN_IF_ERROR(
|
||||||
compiler_visit_argannotation(c, &_Py_ID(return), returns, &annotations_len, loc));
|
compiler_visit_argannotation(c, &_Py_ID(return), returns, annotations_len, loc));
|
||||||
|
|
||||||
if (annotations_len) {
|
return 0;
|
||||||
ADDOP_I(c, loc, BUILD_TUPLE, annotations_len);
|
}
|
||||||
return 1;
|
|
||||||
|
static int
|
||||||
|
compiler_visit_annotations(struct compiler *c, location loc,
|
||||||
|
arguments_ty args, expr_ty returns)
|
||||||
|
{
|
||||||
|
/* Push arg annotation names and values.
|
||||||
|
The expressions are evaluated separately from the rest of the source code.
|
||||||
|
|
||||||
|
Return -1 on error, or a combination of flags to add to the function.
|
||||||
|
*/
|
||||||
|
Py_ssize_t annotations_len = 0;
|
||||||
|
|
||||||
|
PySTEntryObject *ste;
|
||||||
|
if (_PySymtable_LookupOptional(c->c_st, args, &ste) < 0) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
assert(ste != NULL);
|
||||||
|
bool annotations_used = ste->ste_annotations_used;
|
||||||
|
|
||||||
|
if (annotations_used) {
|
||||||
|
if (compiler_setup_annotations_scope(c, loc, (void *)args,
|
||||||
|
ste->ste_name) < 0) {
|
||||||
|
Py_DECREF(ste);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_DECREF(ste);
|
||||||
|
|
||||||
|
if (compiler_visit_annotations_in_scope(c, loc, args, returns, &annotations_len) < 0) {
|
||||||
|
if (annotations_used) {
|
||||||
|
compiler_exit_scope(c);
|
||||||
|
}
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotations_used) {
|
||||||
|
RETURN_IF_ERROR(
|
||||||
|
compiler_leave_annotations_scope(c, loc, annotations_len)
|
||||||
|
);
|
||||||
|
return MAKE_FUNCTION_ANNOTATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2001,7 +2057,7 @@ compiler_type_param_bound_or_default(struct compiler *c, expr_ty e,
|
||||||
identifier name, void *key,
|
identifier name, void *key,
|
||||||
bool allow_starred)
|
bool allow_starred)
|
||||||
{
|
{
|
||||||
if (compiler_enter_scope(c, name, COMPILER_SCOPE_TYPEPARAMS,
|
if (compiler_enter_scope(c, name, COMPILER_SCOPE_ANNOTATIONS,
|
||||||
key, e->lineno) == -1) {
|
key, e->lineno) == -1) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
@ -2220,7 +2276,6 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
|
||||||
asdl_expr_seq *decos;
|
asdl_expr_seq *decos;
|
||||||
asdl_type_param_seq *type_params;
|
asdl_type_param_seq *type_params;
|
||||||
Py_ssize_t funcflags;
|
Py_ssize_t funcflags;
|
||||||
int annotations;
|
|
||||||
int firstlineno;
|
int firstlineno;
|
||||||
|
|
||||||
if (is_async) {
|
if (is_async) {
|
||||||
|
@ -2274,7 +2329,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
|
||||||
if (!type_params_name) {
|
if (!type_params_name) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS,
|
if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_ANNOTATIONS,
|
||||||
(void *)type_params, firstlineno) == -1) {
|
(void *)type_params, firstlineno) == -1) {
|
||||||
Py_DECREF(type_params_name);
|
Py_DECREF(type_params_name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
@ -2286,16 +2341,14 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
annotations = compiler_visit_annotations(c, loc, args, returns);
|
int annotations_flag = compiler_visit_annotations(c, loc, args, returns);
|
||||||
if (annotations < 0) {
|
if (annotations_flag < 0) {
|
||||||
if (is_generic) {
|
if (is_generic) {
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
}
|
}
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (annotations > 0) {
|
funcflags |= annotations_flag;
|
||||||
funcflags |= MAKE_FUNCTION_ANNOTATIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compiler_function_body(c, s, is_async, funcflags, firstlineno) < 0) {
|
if (compiler_function_body(c, s, is_async, funcflags, firstlineno) < 0) {
|
||||||
if (is_generic) {
|
if (is_generic) {
|
||||||
|
@ -2510,7 +2563,7 @@ compiler_class(struct compiler *c, stmt_ty s)
|
||||||
if (!type_params_name) {
|
if (!type_params_name) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS,
|
if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_ANNOTATIONS,
|
||||||
(void *)type_params, firstlineno) == -1) {
|
(void *)type_params, firstlineno) == -1) {
|
||||||
Py_DECREF(type_params_name);
|
Py_DECREF(type_params_name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
@ -2630,7 +2683,7 @@ compiler_typealias(struct compiler *c, stmt_ty s)
|
||||||
if (!type_params_name) {
|
if (!type_params_name) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS,
|
if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_ANNOTATIONS,
|
||||||
(void *)type_params, loc.lineno) == -1) {
|
(void *)type_params, loc.lineno) == -1) {
|
||||||
Py_DECREF(type_params_name);
|
Py_DECREF(type_params_name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
@ -2719,15 +2772,6 @@ check_compare(struct compiler *c, expr_ty e)
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int compare_masks[] = {
|
|
||||||
[Py_LT] = COMPARISON_LESS_THAN,
|
|
||||||
[Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS,
|
|
||||||
[Py_EQ] = COMPARISON_EQUALS,
|
|
||||||
[Py_NE] = COMPARISON_NOT_EQUALS,
|
|
||||||
[Py_GT] = COMPARISON_GREATER_THAN,
|
|
||||||
[Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int compiler_addcompare(struct compiler *c, location loc,
|
static int compiler_addcompare(struct compiler *c, location loc,
|
||||||
cmpop_ty op)
|
cmpop_ty op)
|
||||||
{
|
{
|
||||||
|
@ -6366,7 +6410,8 @@ compiler_annassign(struct compiler *c, stmt_ty s)
|
||||||
{
|
{
|
||||||
location loc = LOC(s);
|
location loc = LOC(s);
|
||||||
expr_ty targ = s->v.AnnAssign.target;
|
expr_ty targ = s->v.AnnAssign.target;
|
||||||
PyObject* mangled;
|
bool future_annotations = c->c_future.ff_features & CO_FUTURE_ANNOTATIONS;
|
||||||
|
PyObject *mangled;
|
||||||
|
|
||||||
assert(s->kind == AnnAssign_kind);
|
assert(s->kind == AnnAssign_kind);
|
||||||
|
|
||||||
|
@ -6384,16 +6429,30 @@ compiler_annassign(struct compiler *c, stmt_ty s)
|
||||||
if (s->v.AnnAssign.simple &&
|
if (s->v.AnnAssign.simple &&
|
||||||
(c->u->u_scope_type == COMPILER_SCOPE_MODULE ||
|
(c->u->u_scope_type == COMPILER_SCOPE_MODULE ||
|
||||||
c->u->u_scope_type == COMPILER_SCOPE_CLASS)) {
|
c->u->u_scope_type == COMPILER_SCOPE_CLASS)) {
|
||||||
if (c->c_future.ff_features & CO_FUTURE_ANNOTATIONS) {
|
if (future_annotations) {
|
||||||
VISIT(c, annexpr, s->v.AnnAssign.annotation)
|
VISIT(c, annexpr, s->v.AnnAssign.annotation);
|
||||||
|
ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__annotations__), names);
|
||||||
|
mangled = _Py_MaybeMangle(c->u->u_private, c->u->u_ste, targ->v.Name.id);
|
||||||
|
ADDOP_LOAD_CONST_NEW(c, loc, mangled);
|
||||||
|
ADDOP(c, loc, STORE_SUBSCR);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VISIT(c, expr, s->v.AnnAssign.annotation);
|
if (c->u->u_deferred_annotations == NULL) {
|
||||||
|
c->u->u_deferred_annotations = PyList_New(0);
|
||||||
|
if (c->u->u_deferred_annotations == NULL) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyObject *ptr = PyLong_FromVoidPtr((void *)s);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
if (PyList_Append(c->u->u_deferred_annotations, ptr) < 0) {
|
||||||
|
Py_DECREF(ptr);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
Py_DECREF(ptr);
|
||||||
}
|
}
|
||||||
ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__annotations__), names);
|
|
||||||
mangled = _Py_MaybeMangle(c->u->u_private, c->u->u_ste, targ->v.Name.id);
|
|
||||||
ADDOP_LOAD_CONST_NEW(c, loc, mangled);
|
|
||||||
ADDOP(c, loc, STORE_SUBSCR);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Attribute_kind:
|
case Attribute_kind:
|
||||||
|
@ -6419,7 +6478,7 @@ compiler_annassign(struct compiler *c, stmt_ty s)
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
/* Annotation is evaluated last. */
|
/* Annotation is evaluated last. */
|
||||||
if (!s->v.AnnAssign.simple && check_annotation(c, s) < 0) {
|
if (future_annotations && !s->v.AnnAssign.simple && check_annotation(c, s) < 0) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
5
Python/executor_cases.c.h
generated
5
Python/executor_cases.c.h
generated
|
@ -4061,6 +4061,11 @@
|
||||||
assert(func_obj->func_defaults == NULL);
|
assert(func_obj->func_defaults == NULL);
|
||||||
func_obj->func_defaults = attr;
|
func_obj->func_defaults = attr;
|
||||||
break;
|
break;
|
||||||
|
case MAKE_FUNCTION_ANNOTATE:
|
||||||
|
assert(PyCallable_Check(attr));
|
||||||
|
assert(func_obj->func_annotate == NULL);
|
||||||
|
func_obj->func_annotate = attr;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
5
Python/generated_cases.c.h
generated
5
Python/generated_cases.c.h
generated
|
@ -5450,6 +5450,11 @@
|
||||||
assert(func_obj->func_defaults == NULL);
|
assert(func_obj->func_defaults == NULL);
|
||||||
func_obj->func_defaults = attr;
|
func_obj->func_defaults = attr;
|
||||||
break;
|
break;
|
||||||
|
case MAKE_FUNCTION_ANNOTATE:
|
||||||
|
assert(PyCallable_Check(attr));
|
||||||
|
assert(func_obj->func_annotate == NULL);
|
||||||
|
func_obj->func_annotate = attr;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
|
||||||
ste->ste_varkeywords = 0;
|
ste->ste_varkeywords = 0;
|
||||||
ste->ste_opt_lineno = 0;
|
ste->ste_opt_lineno = 0;
|
||||||
ste->ste_opt_col_offset = 0;
|
ste->ste_opt_col_offset = 0;
|
||||||
|
ste->ste_annotations_used = 0;
|
||||||
ste->ste_lineno = lineno;
|
ste->ste_lineno = lineno;
|
||||||
ste->ste_col_offset = col_offset;
|
ste->ste_col_offset = col_offset;
|
||||||
ste->ste_end_lineno = end_lineno;
|
ste->ste_end_lineno = end_lineno;
|
||||||
|
@ -132,6 +133,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
|
||||||
ste->ste_can_see_class_scope = 0;
|
ste->ste_can_see_class_scope = 0;
|
||||||
ste->ste_comp_iter_expr = 0;
|
ste->ste_comp_iter_expr = 0;
|
||||||
ste->ste_needs_classdict = 0;
|
ste->ste_needs_classdict = 0;
|
||||||
|
ste->ste_annotation_block = NULL;
|
||||||
|
|
||||||
ste->ste_symbols = PyDict_New();
|
ste->ste_symbols = PyDict_New();
|
||||||
ste->ste_varnames = PyList_New(0);
|
ste->ste_varnames = PyList_New(0);
|
||||||
|
@ -167,6 +169,7 @@ ste_dealloc(PySTEntryObject *ste)
|
||||||
Py_XDECREF(ste->ste_varnames);
|
Py_XDECREF(ste->ste_varnames);
|
||||||
Py_XDECREF(ste->ste_children);
|
Py_XDECREF(ste->ste_children);
|
||||||
Py_XDECREF(ste->ste_directives);
|
Py_XDECREF(ste->ste_directives);
|
||||||
|
Py_XDECREF(ste->ste_annotation_block);
|
||||||
Py_XDECREF(ste->ste_mangled_names);
|
Py_XDECREF(ste->ste_mangled_names);
|
||||||
PyObject_Free(ste);
|
PyObject_Free(ste);
|
||||||
}
|
}
|
||||||
|
@ -245,10 +248,11 @@ static int symtable_visit_alias(struct symtable *st, alias_ty);
|
||||||
static int symtable_visit_comprehension(struct symtable *st, comprehension_ty);
|
static int symtable_visit_comprehension(struct symtable *st, comprehension_ty);
|
||||||
static int symtable_visit_keyword(struct symtable *st, keyword_ty);
|
static int symtable_visit_keyword(struct symtable *st, keyword_ty);
|
||||||
static int symtable_visit_params(struct symtable *st, asdl_arg_seq *args);
|
static int symtable_visit_params(struct symtable *st, asdl_arg_seq *args);
|
||||||
static int symtable_visit_annotation(struct symtable *st, expr_ty annotation);
|
static int symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key);
|
||||||
static int symtable_visit_argannotations(struct symtable *st, asdl_arg_seq *args);
|
static int symtable_visit_argannotations(struct symtable *st, asdl_arg_seq *args);
|
||||||
static int symtable_implicit_arg(struct symtable *st, int pos);
|
static int symtable_implicit_arg(struct symtable *st, int pos);
|
||||||
static int symtable_visit_annotations(struct symtable *st, stmt_ty, arguments_ty, expr_ty);
|
static int symtable_visit_annotations(struct symtable *st, stmt_ty, arguments_ty, expr_ty,
|
||||||
|
struct _symtable_entry *parent_ste);
|
||||||
static int symtable_visit_withitem(struct symtable *st, withitem_ty item);
|
static int symtable_visit_withitem(struct symtable *st, withitem_ty item);
|
||||||
static int symtable_visit_match_case(struct symtable *st, match_case_ty m);
|
static int symtable_visit_match_case(struct symtable *st, match_case_ty m);
|
||||||
static int symtable_visit_pattern(struct symtable *st, pattern_ty s);
|
static int symtable_visit_pattern(struct symtable *st, pattern_ty s);
|
||||||
|
@ -504,6 +508,21 @@ _PySymtable_Lookup(struct symtable *st, void *key)
|
||||||
return (PySTEntryObject *)v;
|
return (PySTEntryObject *)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PySymtable_LookupOptional(struct symtable *st, void *key,
|
||||||
|
PySTEntryObject **out)
|
||||||
|
{
|
||||||
|
PyObject *k = PyLong_FromVoidPtr(key);
|
||||||
|
if (k == NULL) {
|
||||||
|
*out = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int result = PyDict_GetItemRef(st->st_blocks, k, (PyObject **)out);
|
||||||
|
Py_DECREF(k);
|
||||||
|
assert(*out == NULL || PySTEntry_Check(*out));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
long
|
long
|
||||||
_PyST_GetSymbol(PySTEntryObject *ste, PyObject *name)
|
_PyST_GetSymbol(PySTEntryObject *ste, PyObject *name)
|
||||||
{
|
{
|
||||||
|
@ -525,6 +544,7 @@ int
|
||||||
_PyST_IsFunctionLike(PySTEntryObject *ste)
|
_PyST_IsFunctionLike(PySTEntryObject *ste)
|
||||||
{
|
{
|
||||||
return ste->ste_type == FunctionBlock
|
return ste->ste_type == FunctionBlock
|
||||||
|
|| ste->ste_type == AnnotationBlock
|
||||||
|| ste->ste_type == TypeVarBoundBlock
|
|| ste->ste_type == TypeVarBoundBlock
|
||||||
|| ste->ste_type == TypeAliasBlock
|
|| ste->ste_type == TypeAliasBlock
|
||||||
|| ste->ste_type == TypeParamBlock;
|
|| ste->ste_type == TypeParamBlock;
|
||||||
|
@ -1317,20 +1337,12 @@ symtable_exit_block(struct symtable *st)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
|
symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste)
|
||||||
void *ast, int lineno, int col_offset,
|
|
||||||
int end_lineno, int end_col_offset)
|
|
||||||
{
|
{
|
||||||
PySTEntryObject *prev = NULL, *ste;
|
|
||||||
|
|
||||||
ste = ste_new(st, name, block, ast, lineno, col_offset, end_lineno, end_col_offset);
|
|
||||||
if (ste == NULL)
|
|
||||||
return 0;
|
|
||||||
if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) {
|
if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) {
|
||||||
Py_DECREF(ste);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
prev = st->st_cur;
|
PySTEntryObject *prev = st->st_cur;
|
||||||
/* bpo-37757: For now, disallow *all* assignment expressions in the
|
/* bpo-37757: For now, disallow *all* assignment expressions in the
|
||||||
* outermost iterator expression of a comprehension, even those inside
|
* outermost iterator expression of a comprehension, even those inside
|
||||||
* a nested comprehension or a lambda expression.
|
* a nested comprehension or a lambda expression.
|
||||||
|
@ -1340,21 +1352,20 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
|
||||||
}
|
}
|
||||||
/* No need to inherit ste_mangled_names in classes, where all names
|
/* No need to inherit ste_mangled_names in classes, where all names
|
||||||
* are mangled. */
|
* are mangled. */
|
||||||
if (prev && prev->ste_mangled_names != NULL && block != ClassBlock) {
|
if (prev && prev->ste_mangled_names != NULL && ste->ste_type != ClassBlock) {
|
||||||
ste->ste_mangled_names = Py_NewRef(prev->ste_mangled_names);
|
ste->ste_mangled_names = Py_NewRef(prev->ste_mangled_names);
|
||||||
}
|
}
|
||||||
/* The entry is owned by the stack. Borrow it for st_cur. */
|
/* The entry is owned by the stack. Borrow it for st_cur. */
|
||||||
Py_DECREF(ste);
|
|
||||||
st->st_cur = ste;
|
st->st_cur = ste;
|
||||||
|
|
||||||
/* Annotation blocks shouldn't have any affect on the symbol table since in
|
/* If "from __future__ import annotations" is active,
|
||||||
* the compilation stage, they will all be transformed to strings. They are
|
* annotation blocks shouldn't have any affect on the symbol table since in
|
||||||
* only created if future 'annotations' feature is activated. */
|
* the compilation stage, they will all be transformed to strings. */
|
||||||
if (block == AnnotationBlock) {
|
if (st->st_future->ff_features & CO_FUTURE_ANNOTATIONS && ste->ste_type == AnnotationBlock) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block == ModuleBlock)
|
if (ste->ste_type == ModuleBlock)
|
||||||
st->st_global = st->st_cur->ste_symbols;
|
st->st_global = st->st_cur->ste_symbols;
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
|
@ -1365,6 +1376,20 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
|
||||||
|
void *ast, int lineno, int col_offset,
|
||||||
|
int end_lineno, int end_col_offset)
|
||||||
|
{
|
||||||
|
PySTEntryObject *ste = ste_new(st, name, block, ast,
|
||||||
|
lineno, col_offset, end_lineno, end_col_offset);
|
||||||
|
if (ste == NULL)
|
||||||
|
return 0;
|
||||||
|
int result = symtable_enter_existing_block(st, ste);
|
||||||
|
Py_DECREF(ste);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
symtable_lookup_entry(struct symtable *st, PySTEntryObject *ste, PyObject *name)
|
symtable_lookup_entry(struct symtable *st, PySTEntryObject *ste, PyObject *name)
|
||||||
{
|
{
|
||||||
|
@ -1643,7 +1668,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
switch (s->kind) {
|
switch (s->kind) {
|
||||||
case FunctionDef_kind:
|
case FunctionDef_kind: {
|
||||||
if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL, LOCATION(s)))
|
if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL, LOCATION(s)))
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
if (s->v.FunctionDef.args->defaults)
|
if (s->v.FunctionDef.args->defaults)
|
||||||
|
@ -1665,13 +1690,22 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
}
|
}
|
||||||
VISIT_SEQ(st, type_param, s->v.FunctionDef.type_params);
|
VISIT_SEQ(st, type_param, s->v.FunctionDef.type_params);
|
||||||
}
|
}
|
||||||
|
PySTEntryObject *new_ste = ste_new(st, s->v.FunctionDef.name, FunctionBlock, (void *)s,
|
||||||
|
LOCATION(s));
|
||||||
|
if (!new_ste) {
|
||||||
|
VISIT_QUIT(st, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args,
|
if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args,
|
||||||
s->v.FunctionDef.returns))
|
s->v.FunctionDef.returns, new_ste)) {
|
||||||
|
Py_DECREF(new_ste);
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
if (!symtable_enter_block(st, s->v.FunctionDef.name,
|
}
|
||||||
FunctionBlock, (void *)s,
|
if (!symtable_enter_existing_block(st, new_ste)) {
|
||||||
LOCATION(s)))
|
Py_DECREF(new_ste);
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
|
}
|
||||||
|
Py_DECREF(new_ste);
|
||||||
VISIT(st, arguments, s->v.FunctionDef.args);
|
VISIT(st, arguments, s->v.FunctionDef.args);
|
||||||
VISIT_SEQ(st, stmt, s->v.FunctionDef.body);
|
VISIT_SEQ(st, stmt, s->v.FunctionDef.body);
|
||||||
if (!symtable_exit_block(st))
|
if (!symtable_exit_block(st))
|
||||||
|
@ -1681,6 +1715,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case ClassDef_kind: {
|
case ClassDef_kind: {
|
||||||
PyObject *tmp;
|
PyObject *tmp;
|
||||||
if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL, LOCATION(s)))
|
if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL, LOCATION(s)))
|
||||||
|
@ -1776,6 +1811,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
VISIT(st, expr, s->v.Assign.value);
|
VISIT(st, expr, s->v.Assign.value);
|
||||||
break;
|
break;
|
||||||
case AnnAssign_kind:
|
case AnnAssign_kind:
|
||||||
|
st->st_cur->ste_annotations_used = 1;
|
||||||
if (s->v.AnnAssign.target->kind == Name_kind) {
|
if (s->v.AnnAssign.target->kind == Name_kind) {
|
||||||
expr_ty e_name = s->v.AnnAssign.target;
|
expr_ty e_name = s->v.AnnAssign.target;
|
||||||
long cur = symtable_lookup(st, e_name->v.Name.id);
|
long cur = symtable_lookup(st, e_name->v.Name.id);
|
||||||
|
@ -1810,7 +1846,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
else {
|
else {
|
||||||
VISIT(st, expr, s->v.AnnAssign.target);
|
VISIT(st, expr, s->v.AnnAssign.target);
|
||||||
}
|
}
|
||||||
if (!symtable_visit_annotation(st, s->v.AnnAssign.annotation)) {
|
if (!symtable_visit_annotation(st, s->v.AnnAssign.annotation,
|
||||||
|
(void *)((uintptr_t)st->st_cur->ste_id + 1))) {
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1960,7 +1997,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
VISIT_SEQ(st, withitem, s->v.With.items);
|
VISIT_SEQ(st, withitem, s->v.With.items);
|
||||||
VISIT_SEQ(st, stmt, s->v.With.body);
|
VISIT_SEQ(st, stmt, s->v.With.body);
|
||||||
break;
|
break;
|
||||||
case AsyncFunctionDef_kind:
|
case AsyncFunctionDef_kind: {
|
||||||
if (!symtable_add_def(st, s->v.AsyncFunctionDef.name, DEF_LOCAL, LOCATION(s)))
|
if (!symtable_add_def(st, s->v.AsyncFunctionDef.name, DEF_LOCAL, LOCATION(s)))
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
if (s->v.AsyncFunctionDef.args->defaults)
|
if (s->v.AsyncFunctionDef.args->defaults)
|
||||||
|
@ -1983,14 +2020,21 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
}
|
}
|
||||||
VISIT_SEQ(st, type_param, s->v.AsyncFunctionDef.type_params);
|
VISIT_SEQ(st, type_param, s->v.AsyncFunctionDef.type_params);
|
||||||
}
|
}
|
||||||
|
PySTEntryObject *new_ste = ste_new(st, s->v.FunctionDef.name, FunctionBlock, (void *)s,
|
||||||
|
LOCATION(s));
|
||||||
|
if (!new_ste) {
|
||||||
|
VISIT_QUIT(st, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args,
|
if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args,
|
||||||
s->v.AsyncFunctionDef.returns))
|
s->v.AsyncFunctionDef.returns, new_ste))
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
if (!symtable_enter_block(st, s->v.AsyncFunctionDef.name,
|
if (!symtable_enter_existing_block(st, new_ste)) {
|
||||||
FunctionBlock, (void *)s,
|
Py_DECREF(new_ste);
|
||||||
s->lineno, s->col_offset,
|
|
||||||
s->end_lineno, s->end_col_offset))
|
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
|
}
|
||||||
|
Py_DECREF(new_ste);
|
||||||
|
|
||||||
st->st_cur->ste_coroutine = 1;
|
st->st_cur->ste_coroutine = 1;
|
||||||
VISIT(st, arguments, s->v.AsyncFunctionDef.args);
|
VISIT(st, arguments, s->v.AsyncFunctionDef.args);
|
||||||
VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body);
|
VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body);
|
||||||
|
@ -2001,6 +2045,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case AsyncWith_kind:
|
case AsyncWith_kind:
|
||||||
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
|
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
|
||||||
VISIT_SEQ(st, stmt, s->v.AsyncWith.body);
|
VISIT_SEQ(st, stmt, s->v.AsyncWith.body);
|
||||||
|
@ -2444,18 +2489,44 @@ symtable_visit_params(struct symtable *st, asdl_arg_seq *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
symtable_visit_annotation(struct symtable *st, expr_ty annotation)
|
symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key)
|
||||||
{
|
{
|
||||||
int future_annotations = st->st_future->ff_features & CO_FUTURE_ANNOTATIONS;
|
struct _symtable_entry *parent_ste = st->st_cur;
|
||||||
if (future_annotations &&
|
if (parent_ste->ste_annotation_block == NULL) {
|
||||||
!symtable_enter_block(st, &_Py_ID(_annotation), AnnotationBlock,
|
_Py_block_ty current_type = parent_ste->ste_type;
|
||||||
(void *)annotation, annotation->lineno,
|
if (!symtable_enter_block(st, &_Py_ID(__annotate__), AnnotationBlock,
|
||||||
annotation->col_offset, annotation->end_lineno,
|
key, LOCATION(annotation))) {
|
||||||
annotation->end_col_offset)) {
|
VISIT_QUIT(st, 0);
|
||||||
VISIT_QUIT(st, 0);
|
}
|
||||||
|
parent_ste->ste_annotation_block =
|
||||||
|
(struct _symtable_entry *)Py_NewRef(st->st_cur);
|
||||||
|
int future_annotations = st->st_future->ff_features & CO_FUTURE_ANNOTATIONS;
|
||||||
|
if (current_type == ClassBlock && !future_annotations) {
|
||||||
|
st->st_cur->ste_can_see_class_scope = 1;
|
||||||
|
if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(annotation))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_Py_DECLARE_STR(format, ".format");
|
||||||
|
// The generated __annotate__ function takes a single parameter with the
|
||||||
|
// internal name ".format".
|
||||||
|
if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM,
|
||||||
|
LOCATION(annotation))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!symtable_add_def(st, &_Py_STR(format), USE,
|
||||||
|
LOCATION(annotation))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!symtable_enter_existing_block(st, parent_ste->ste_annotation_block)) {
|
||||||
|
VISIT_QUIT(st, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
VISIT(st, expr, annotation);
|
VISIT(st, expr, annotation);
|
||||||
if (future_annotations && !symtable_exit_block(st)) {
|
if (!symtable_exit_block(st)) {
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2471,37 +2542,58 @@ symtable_visit_argannotations(struct symtable *st, asdl_arg_seq *args)
|
||||||
|
|
||||||
for (i = 0; i < asdl_seq_LEN(args); i++) {
|
for (i = 0; i < asdl_seq_LEN(args); i++) {
|
||||||
arg_ty arg = (arg_ty)asdl_seq_GET(args, i);
|
arg_ty arg = (arg_ty)asdl_seq_GET(args, i);
|
||||||
if (arg->annotation)
|
if (arg->annotation) {
|
||||||
|
st->st_cur->ste_annotations_used = 1;
|
||||||
VISIT(st, expr, arg->annotation);
|
VISIT(st, expr, arg->annotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
symtable_visit_annotations(struct symtable *st, stmt_ty o, arguments_ty a, expr_ty returns)
|
symtable_visit_annotations(struct symtable *st, stmt_ty o, arguments_ty a, expr_ty returns,
|
||||||
|
struct _symtable_entry *function_ste)
|
||||||
{
|
{
|
||||||
int future_annotations = st->st_future->ff_features & CO_FUTURE_ANNOTATIONS;
|
int is_in_class = st->st_cur->ste_can_see_class_scope;
|
||||||
if (future_annotations &&
|
_Py_block_ty current_type = st->st_cur->ste_type;
|
||||||
!symtable_enter_block(st, &_Py_ID(_annotation), AnnotationBlock,
|
if (!symtable_enter_block(st, &_Py_ID(__annotate__), AnnotationBlock,
|
||||||
(void *)o, o->lineno, o->col_offset, o->end_lineno,
|
(void *)a, LOCATION(o))) {
|
||||||
o->end_col_offset)) {
|
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
|
if (is_in_class || current_type == ClassBlock) {
|
||||||
|
st->st_cur->ste_can_see_class_scope = 1;
|
||||||
|
if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(o))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_Py_DECLARE_STR(format, ".format");
|
||||||
|
// We need to insert code that reads this "parameter" to the function.
|
||||||
|
if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM, LOCATION(o))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!symtable_add_def(st, &_Py_STR(format), USE, LOCATION(o))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (a->posonlyargs && !symtable_visit_argannotations(st, a->posonlyargs))
|
if (a->posonlyargs && !symtable_visit_argannotations(st, a->posonlyargs))
|
||||||
return 0;
|
return 0;
|
||||||
if (a->args && !symtable_visit_argannotations(st, a->args))
|
if (a->args && !symtable_visit_argannotations(st, a->args))
|
||||||
return 0;
|
return 0;
|
||||||
if (a->vararg && a->vararg->annotation)
|
if (a->vararg && a->vararg->annotation) {
|
||||||
|
st->st_cur->ste_annotations_used = 1;
|
||||||
VISIT(st, expr, a->vararg->annotation);
|
VISIT(st, expr, a->vararg->annotation);
|
||||||
if (a->kwarg && a->kwarg->annotation)
|
}
|
||||||
|
if (a->kwarg && a->kwarg->annotation) {
|
||||||
|
st->st_cur->ste_annotations_used = 1;
|
||||||
VISIT(st, expr, a->kwarg->annotation);
|
VISIT(st, expr, a->kwarg->annotation);
|
||||||
|
}
|
||||||
if (a->kwonlyargs && !symtable_visit_argannotations(st, a->kwonlyargs))
|
if (a->kwonlyargs && !symtable_visit_argannotations(st, a->kwonlyargs))
|
||||||
return 0;
|
return 0;
|
||||||
if (future_annotations && !symtable_exit_block(st)) {
|
if (returns) {
|
||||||
VISIT_QUIT(st, 0);
|
st->st_cur->ste_annotations_used = 1;
|
||||||
|
VISIT(st, expr, returns);
|
||||||
}
|
}
|
||||||
if (returns && !symtable_visit_annotation(st, returns)) {
|
if (!symtable_exit_block(st)) {
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2733,7 +2825,7 @@ symtable_visit_dictcomp(struct symtable *st, expr_ty e)
|
||||||
static int
|
static int
|
||||||
symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_ty e)
|
symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_ty e)
|
||||||
{
|
{
|
||||||
enum _block_type type = st->st_cur->ste_type;
|
_Py_block_ty type = st->st_cur->ste_type;
|
||||||
if (type == AnnotationBlock)
|
if (type == AnnotationBlock)
|
||||||
PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name);
|
PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name);
|
||||||
else if (type == TypeVarBoundBlock)
|
else if (type == TypeVarBoundBlock)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue