mirror of
https://github.com/python/cpython.git
synced 2025-11-24 20:30:18 +00:00
gh-130907: Treat all module-level annotations as conditional (#131550)
This commit is contained in:
parent
5bf0f3666e
commit
922049b613
21 changed files with 221 additions and 53 deletions
|
|
@ -2026,6 +2026,10 @@ dummy_func(
|
|||
}
|
||||
}
|
||||
|
||||
pseudo(ANNOTATIONS_PLACEHOLDER, (--)) = {
|
||||
NOP,
|
||||
};
|
||||
|
||||
inst(DICT_UPDATE, (dict, unused[oparg - 1], update -- dict, unused[oparg - 1])) {
|
||||
PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict);
|
||||
PyObject *update_o = PyStackRef_AsPyObjectBorrow(update);
|
||||
|
|
|
|||
|
|
@ -654,6 +654,9 @@ codegen_enter_scope(compiler *c, identifier name, int scope_type,
|
|||
loc.lineno = 0;
|
||||
}
|
||||
ADDOP_I(c, loc, RESUME, RESUME_AT_FUNC_START);
|
||||
if (scope_type == COMPILE_SCOPE_MODULE) {
|
||||
ADDOP(c, loc, ANNOTATIONS_PLACEHOLDER);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -792,6 +795,14 @@ codegen_process_deferred_annotations(compiler *c, location loc)
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
int scope_type = SCOPE_TYPE(c);
|
||||
bool need_separate_block = scope_type == COMPILE_SCOPE_MODULE;
|
||||
if (need_separate_block) {
|
||||
if (_PyCompile_StartAnnotationSetup(c) == ERROR) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -800,7 +811,6 @@ codegen_process_deferred_annotations(compiler *c, location loc)
|
|||
PySTEntryObject *ste = SYMTABLE_ENTRY(c);
|
||||
assert(ste->ste_annotation_block != NULL);
|
||||
void *key = (void *)((uintptr_t)ste->ste_id + 1);
|
||||
int scope_type = SCOPE_TYPE(c);
|
||||
if (codegen_setup_annotations_scope(c, loc, key,
|
||||
ste->ste_annotation_block->ste_name) < 0) {
|
||||
goto error;
|
||||
|
|
@ -820,6 +830,10 @@ codegen_process_deferred_annotations(compiler *c, location loc)
|
|||
ste->ste_type == ClassBlock ? &_Py_ID(__annotate_func__) : &_Py_ID(__annotate__),
|
||||
Store));
|
||||
|
||||
if (need_separate_block) {
|
||||
RETURN_IF_ERROR(_PyCompile_EndAnnotationSetup(c));
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
error:
|
||||
Py_XDECREF(deferred_anno);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ struct compiler_unit {
|
|||
long u_next_conditional_annotation_index; /* index of the next conditional annotation */
|
||||
|
||||
instr_sequence *u_instr_sequence; /* codegen output */
|
||||
instr_sequence *u_stashed_instr_sequence; /* temporarily stashed parent instruction sequence */
|
||||
|
||||
int u_nfblocks;
|
||||
int u_in_inlined_comp;
|
||||
|
|
@ -178,6 +179,7 @@ static void
|
|||
compiler_unit_free(struct compiler_unit *u)
|
||||
{
|
||||
Py_CLEAR(u->u_instr_sequence);
|
||||
Py_CLEAR(u->u_stashed_instr_sequence);
|
||||
Py_CLEAR(u->u_ste);
|
||||
Py_CLEAR(u->u_metadata.u_name);
|
||||
Py_CLEAR(u->u_metadata.u_qualname);
|
||||
|
|
@ -681,6 +683,7 @@ _PyCompile_EnterScope(compiler *c, identifier name, int scope_type,
|
|||
compiler_unit_free(u);
|
||||
return ERROR;
|
||||
}
|
||||
u->u_stashed_instr_sequence = NULL;
|
||||
|
||||
/* Push the old compiler_unit on the stack. */
|
||||
if (c->u) {
|
||||
|
|
@ -1154,7 +1157,7 @@ _PyCompile_AddDeferredAnnotation(compiler *c, stmt_ty s,
|
|||
}
|
||||
Py_DECREF(ptr);
|
||||
PyObject *index;
|
||||
if (c->u->u_in_conditional_block) {
|
||||
if (c->u->u_scope_type == COMPILE_SCOPE_MODULE || c->u->u_in_conditional_block) {
|
||||
index = PyLong_FromLong(c->u->u_next_conditional_annotation_index);
|
||||
if (index == NULL) {
|
||||
return ERROR;
|
||||
|
|
@ -1231,6 +1234,35 @@ _PyCompile_InstrSequence(compiler *c)
|
|||
return c->u->u_instr_sequence;
|
||||
}
|
||||
|
||||
int
|
||||
_PyCompile_StartAnnotationSetup(struct _PyCompiler *c)
|
||||
{
|
||||
instr_sequence *new_seq = (instr_sequence *)_PyInstructionSequence_New();
|
||||
if (new_seq == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
assert(c->u->u_stashed_instr_sequence == NULL);
|
||||
c->u->u_stashed_instr_sequence = c->u->u_instr_sequence;
|
||||
c->u->u_instr_sequence = new_seq;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
_PyCompile_EndAnnotationSetup(struct _PyCompiler *c)
|
||||
{
|
||||
assert(c->u->u_stashed_instr_sequence != NULL);
|
||||
instr_sequence *parent_seq = c->u->u_stashed_instr_sequence;
|
||||
instr_sequence *anno_seq = c->u->u_instr_sequence;
|
||||
c->u->u_stashed_instr_sequence = NULL;
|
||||
c->u->u_instr_sequence = parent_seq;
|
||||
if (_PyInstructionSequence_SetAnnotationsCode(parent_seq, anno_seq) == ERROR) {
|
||||
Py_DECREF(anno_seq);
|
||||
return ERROR;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyCompile_FutureFeatures(compiler *c)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3847,16 +3847,38 @@ _PyCfg_FromInstructionSequence(_PyInstructionSequence *seq)
|
|||
seq->s_instrs[instr->i_oparg].i_target = 1;
|
||||
}
|
||||
}
|
||||
int offset = 0;
|
||||
for (int i = 0; i < seq->s_used; i++) {
|
||||
_PyInstruction *instr = &seq->s_instrs[i];
|
||||
if (instr->i_opcode == ANNOTATIONS_PLACEHOLDER) {
|
||||
if (seq->s_annotations_code != NULL) {
|
||||
assert(seq->s_annotations_code->s_labelmap_size == 0
|
||||
&& seq->s_annotations_code->s_nested == NULL);
|
||||
for (int j = 0; j < seq->s_annotations_code->s_used; j++) {
|
||||
_PyInstruction *ann_instr = &seq->s_annotations_code->s_instrs[j];
|
||||
assert(!HAS_TARGET(ann_instr->i_opcode));
|
||||
if (_PyCfgBuilder_Addop(g, ann_instr->i_opcode, ann_instr->i_oparg, ann_instr->i_loc) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
offset += seq->s_annotations_code->s_used - 1;
|
||||
}
|
||||
else {
|
||||
offset -= 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (instr->i_target) {
|
||||
jump_target_label lbl_ = {i};
|
||||
jump_target_label lbl_ = {i + offset};
|
||||
if (_PyCfgBuilder_UseLabel(g, lbl_) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
int opcode = instr->i_opcode;
|
||||
int oparg = instr->i_oparg;
|
||||
if (HAS_TARGET(opcode)) {
|
||||
oparg += offset;
|
||||
}
|
||||
if (_PyCfgBuilder_Addop(g, opcode, oparg, instr->i_loc) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,15 @@ _PyInstructionSequence_InsertInstruction(instr_sequence *seq, int pos,
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
_PyInstructionSequence_SetAnnotationsCode(instr_sequence *seq,
|
||||
instr_sequence *annotations)
|
||||
{
|
||||
assert(seq->s_annotations_code == NULL);
|
||||
seq->s_annotations_code = annotations;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
_PyInstructionSequence_AddNested(instr_sequence *seq, instr_sequence *nested)
|
||||
{
|
||||
|
|
@ -178,6 +187,12 @@ PyInstructionSequence_Fini(instr_sequence *seq) {
|
|||
|
||||
PyMem_Free(seq->s_instrs);
|
||||
seq->s_instrs = NULL;
|
||||
|
||||
if (seq->s_annotations_code != NULL) {
|
||||
PyInstructionSequence_Fini(seq->s_annotations_code);
|
||||
Py_CLEAR(seq->s_annotations_code);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
|
@ -200,6 +215,7 @@ inst_seq_create(void)
|
|||
seq->s_labelmap = NULL;
|
||||
seq->s_labelmap_size = 0;
|
||||
seq->s_nested = NULL;
|
||||
seq->s_annotations_code = NULL;
|
||||
|
||||
PyObject_GC_Track(seq);
|
||||
return seq;
|
||||
|
|
@ -414,6 +430,7 @@ inst_seq_traverse(PyObject *op, visitproc visit, void *arg)
|
|||
{
|
||||
_PyInstructionSequence *seq = (_PyInstructionSequence *)op;
|
||||
Py_VISIT(seq->s_nested);
|
||||
Py_VISIT((PyObject *)seq->s_annotations_code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +439,7 @@ inst_seq_clear(PyObject *op)
|
|||
{
|
||||
_PyInstructionSequence *seq = (_PyInstructionSequence *)op;
|
||||
Py_CLEAR(seq->s_nested);
|
||||
Py_CLEAR(seq->s_annotations_code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2749,8 +2749,10 @@ symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key)
|
|||
// Annotations in local scopes are not executed and should not affect the symtable
|
||||
bool is_unevaluated = st->st_cur->ste_type == FunctionBlock;
|
||||
|
||||
if ((st->st_cur->ste_type == ClassBlock || st->st_cur->ste_type == ModuleBlock)
|
||||
&& st->st_cur->ste_in_conditional_block
|
||||
// Module-level annotations are always considered conditional because the module
|
||||
// may be partially executed.
|
||||
if ((((st->st_cur->ste_type == ClassBlock && st->st_cur->ste_in_conditional_block)
|
||||
|| st->st_cur->ste_type == ModuleBlock))
|
||||
&& !st->st_cur->ste_has_conditional_annotations)
|
||||
{
|
||||
st->st_cur->ste_has_conditional_annotations = 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue