-
-
Notifications
You must be signed in to change notification settings - Fork 34.4k
gh-145019: improve SyntaxError when match patterns bind different names
#145939
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Improve :exc:`SyntaxError` when :keyword:`match` alternative patterns bind | ||
| different names. Patch by Bénédikt Tran. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6270,6 +6270,8 @@ codegen_pattern_or(compiler *c, pattern_ty p, pattern_context *pc) | |||||
| NEW_JUMP_TARGET_LABEL(c, end); | ||||||
| Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); | ||||||
| assert(size > 1); | ||||||
| PyObject *mismatched_names = NULL; | ||||||
| Py_ssize_t mismatch_index = 0; | ||||||
| // We're going to be messing with pc. Keep the original info handy: | ||||||
| pattern_context old_pc = *pc; | ||||||
| Py_INCREF(pc->stores); | ||||||
|
|
@@ -6304,6 +6306,8 @@ codegen_pattern_or(compiler *c, pattern_ty p, pattern_context *pc) | |||||
| control = Py_NewRef(pc->stores); | ||||||
| } | ||||||
| else if (nstores != PyList_GET_SIZE(control)) { | ||||||
| mismatch_index = i; | ||||||
| mismatched_names = Py_NewRef(pc->stores); | ||||||
| goto diff; | ||||||
| } | ||||||
| else if (nstores) { | ||||||
|
|
@@ -6314,6 +6318,8 @@ codegen_pattern_or(compiler *c, pattern_ty p, pattern_context *pc) | |||||
| Py_ssize_t istores = PySequence_Index(pc->stores, name); | ||||||
| if (istores < 0) { | ||||||
| PyErr_Clear(); | ||||||
| mismatch_index = i; | ||||||
| mismatched_names = Py_NewRef(pc->stores); | ||||||
| goto diff; | ||||||
| } | ||||||
| if (icontrol != istores) { | ||||||
|
|
@@ -6405,10 +6411,26 @@ codegen_pattern_or(compiler *c, pattern_ty p, pattern_context *pc) | |||||
| // Pop the copy of the subject: | ||||||
| ADDOP(c, LOC(p), POP_TOP); | ||||||
| return SUCCESS; | ||||||
| diff: | ||||||
| _PyCompile_Error(c, LOC(p), "alternative patterns bind different names"); | ||||||
| diff:; | ||||||
| PyObject *no_names = NULL; | ||||||
| if (PyList_GET_SIZE(control) == 0 || !mismatched_names) { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I am missing something here the condition Similarly, the ternary at line 6428 ( |
||||||
| no_names = PyUnicode_FromString("no names"); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This guy is only substituted when the first pattern ( Showing
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh good catch. I should have increased test coverage. I will put more cases to exercise this path. Thanks!
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is freed later before the |
||||||
| if (no_names == NULL) { | ||||||
| goto error; | ||||||
| } | ||||||
| } | ||||||
| _PyCompile_Error( | ||||||
| c, LOC(p), | ||||||
| "alternative patterns bind different names " | ||||||
| "(first pattern binds %S, pattern %zd binds %S)", | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: rather than "first pattern... pattern X...", let's be consistent. "second/third/etc pattern" is tricky, so:
Suggested change
|
||||||
| PyList_GET_SIZE(control) == 0 ? no_names : control, | ||||||
| mismatch_index + 1, | ||||||
| mismatched_names == NULL ? no_names : mismatched_names | ||||||
| ); | ||||||
| Py_XDECREF(no_names); | ||||||
| error: | ||||||
| PyMem_Free(old_pc.fail_pop); | ||||||
| Py_XDECREF(mismatched_names); | ||||||
| Py_DECREF(old_pc.stores); | ||||||
| Py_XDECREF(control); | ||||||
| return ERROR; | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually wondered whether it was better to display the list as is or use some join to have a string. How do you feel about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you give an example?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently:l (I think)
Suggestion:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think either current or number 1. Current will be easier :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes current is simple and easier to parse. It may however be better if we remove common entries (unless it is already done).