Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-101517: propagate lasti with RERAISE 1 in except* handling to get currect line numbers #103529

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,52 @@ def func():
(7, 'line'),
(7, 'return')])

def test_try_except_star_named_exception_not_matched(self):

def func():
try:
try:
raise ValueError(3)
except* TypeError as e:
5
except ValueError:
7

self.run_and_compare(func,
[(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(3, 'exception'),
(4, 'line'),
(6, 'line'),
(7, 'line'),
(7, 'return')])


def test_try_except_star_named_exception_partial_match(self):

def func():
try:
try:
raise ExceptionGroup("eg", [ValueError(4), TypeError(5)])
except* TypeError as e:
5
except ExceptionGroup:
return 7

self.run_and_compare(func,
[(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(3, 'exception'),
(4, 'line'),
(5, 'line'),
(6, 'line'),
(7, 'line'),
(7, 'return')])

def test_try_except_star_nested(self):

def func():
Expand Down
93 changes: 55 additions & 38 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3033,47 +3033,61 @@ compiler_try_except(struct compiler *c, stmt_ty s)
at the right; 'tb' is trace-back info, 'val' the exception instance,
and 'typ' the exception's type.)

Value stack Label Instruction Argument
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
[] JUMP L0
The following syblos are used below:

[exc] L1: BUILD_LIST ) list for raised/reraised excs ("result")
[orig, res] COPY 2 ) make a copy of the original EG
i: the lasti of the current exception
exc': the handled exception (if any) when the current exception was raised
exc/orig: the exception that was caught by this try-except* construct
res: list of exceptions raised/reraised in the except* clauses
match/rest: the results of split in an except* clause
i', v: an exception raised in the try-except (and its lasti)

[orig, res, exc] <evaluate E1>
[orig, res, exc, E1] CHECK_EG_MATCH
[orig, res, rest/exc, match?] COPY 1
[orig, res, rest/exc, match?, match?] POP_JUMP_IF_NOT_NONE H1
[orig, res, exc, None] POP_TOP
[orig, res, exc] JUMP L2

[orig, res, rest, match] H1: <assign to V1> (or POP if no V1)
Value stack Label Instruction Argument
[] SETUP_CLEANUP L1
[] <code for S>
[] POP_BLOCK
[] JUMP L0

[orig, res, rest] SETUP_FINALLY R1
[orig, res, rest] <code for S1>
[orig, res, rest] JUMP L2
[i, exc', exc] L1: BUILD_LIST ) list of (re)raised excs
[i, exc', orig, res] COPY 2 ) copy of original EG

[orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
[orig, res, rest, i] POP
[i, exc', orig, res, exc] <evaluate E1>
[i, exc', orig, res, exc, E1] CHECK_EG_MATCH
[i, exc', orig, res, rest/exc, match] COPY 1
[i, exc', orig, res, rest/exc, match, match] POP_JUMP_IF_NOT_NONE H1
[i, exc', orig, res, exc, None] POP_TOP
[i, exc', orig, res, exc] JUMP L2

[orig, res, rest] L2: <evaluate E2>
[i, exc', orig, res, rest, match] H1: <assign to V1> (or POP if no V1)

[i, exc', orig, res, rest] SETUP_CLEANUP R1
[i, exc', orig, res, rest] <code for S1>
[i, exc', orig, res, rest] JUMP L2

[i, exc', orig, res, rest, i', v] R1: LIST_APPEND 3 ) exc raised in except* body --> res
[i, exc', orig, res, rest, i'] SWAP 6 ) update lasti

[i', exc', orig, res, rest, i] POP

[i, exc', orig, res, rest] L2: <evaluate E2>
.............................etc.......................

[orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)
[i, exc', orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)

[orig, res] CALL_INTRINSIC_2 PREP_RERAISE_STAR
[exc] COPY 1
[exc, exc] POP_JUMP_IF_NOT_NONE RER
[exc] POP_TOP
[] JUMP L0
[i, exc', orig, res] CALL_INTRINSIC_2 PREP_RERAISE_STAR
[i, exc', exc] COPY 1
[i, exc', exc, exc] POP_JUMP_IF_NOT_NONE RER
[i, exc', exc] POP_TOP
[i, exc'] POP_TOP
[i] POP_TOP
[] JUMP L0

[exc] RER: SWAP 2
[exc, prev_exc_info] POP_EXCEPT
[exc] RERAISE 0
[i, exc', exc] RER: SWAP 2
[i, exc, exc'] POP_EXCEPT
[i, exc] RERAISE 1

[] L0: <next statement>
[] L0: <next statement>
*/
static int
compiler_try_star_except(struct compiler *c, stmt_ty s)
Expand All @@ -3087,7 +3101,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
NEW_JUMP_TARGET_LABEL(c, cleanup);
NEW_JUMP_TARGET_LABEL(c, reraise_star);

ADDOP_JUMP(c, loc, SETUP_FINALLY, except);
ADDOP_JUMP(c, loc, SETUP_CLEANUP, except);

USE_LABEL(c, body);
RETURN_IF_ERROR(
Expand Down Expand Up @@ -3118,12 +3132,12 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
if (i == 0) {
/* create empty list for exceptions raised/reraise in the except* blocks */
/*
[orig] BUILD_LIST
[i, orig] BUILD_LIST
*/
/* Create a copy of the original EG */
/*
[orig, []] COPY 2
[orig, [], exc]
[i, orig, []] COPY 2
[i, orig, [], exc]
*/
ADDOP_I(c, loc, BUILD_LIST, 0);
ADDOP_I(c, loc, COPY, 2);
Expand All @@ -3133,7 +3147,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP(c, loc, CHECK_EG_MATCH);
ADDOP_I(c, loc, COPY, 1);
ADDOP_JUMP(c, loc, POP_JUMP_IF_NOT_NONE, handle_match);
ADDOP(c, loc, POP_TOP); // match
ADDOP(c, loc, POP_TOP); // match (None)
ADDOP_JUMP(c, loc, JUMP, except);
}

Expand Down Expand Up @@ -3196,7 +3210,8 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)

/* add exception raised to the res list */
ADDOP_I(c, NO_LOCATION, LIST_APPEND, 3); // exc
ADDOP(c, NO_LOCATION, POP_TOP); // lasti
ADDOP_I(c, NO_LOCATION, SWAP, 6); // save the new lasti
ADDOP(c, NO_LOCATION, POP_TOP); // remove the old lasti
ADDOP_JUMP(c, NO_LOCATION, JUMP, except);

USE_LABEL(c, except);
Expand All @@ -3217,7 +3232,9 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_NOT_NONE, reraise);

/* Nothing to reraise */
ADDOP(c, NO_LOCATION, POP_TOP);
ADDOP(c, NO_LOCATION, POP_TOP); // exc (None)
ADDOP_I(c, NO_LOCATION, SWAP, 2); // [lasti, exc'] --> [exc', lasti]
ADDOP(c, NO_LOCATION, POP_TOP); // lasti
ADDOP(c, NO_LOCATION, POP_BLOCK);
ADDOP(c, NO_LOCATION, POP_EXCEPT);
ADDOP_JUMP(c, NO_LOCATION, JUMP, end);
Expand All @@ -3226,7 +3243,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP(c, NO_LOCATION, POP_BLOCK);
ADDOP_I(c, NO_LOCATION, SWAP, 2);
ADDOP(c, NO_LOCATION, POP_EXCEPT);
ADDOP_I(c, NO_LOCATION, RERAISE, 0);
ADDOP_I(c, NO_LOCATION, RERAISE, 1);

USE_LABEL(c, cleanup);
POP_EXCEPT_AND_RERAISE(c, NO_LOCATION);
Expand Down