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

bpo-42128: Structural Pattern Matching (PEP 634) #22917

Merged
merged 260 commits into from
Feb 26, 2021

Conversation

brandtbucher
Copy link
Member

@brandtbucher brandtbucher commented Oct 23, 2020

PEP 634 has now been accepted, and we'd like to get this into the next alpha.

Several people have volunteered to review the implementation, since it's so huge. Other reviews are very welcome, if anybody has a bit of time to pitch in. This touches tons of stuff: the parser, the compiler, the VM, the builtins, the stdlib, the tests... I'd like as many eyeballs as possible!

https://bugs.python.org/issue42128

@pablogsal
Copy link
Member

when's the latest you'd be comfortable merging this before the release?

Do you mean before the alpha release? Given that a lot of people would be waiting for the next alpha to play with this, we can merge it even on the same day if is required. We can stay in contact via email if it comes to that. Or are you referring to beta freeze?

In any case, I would like to make a review pass, but these weeks I have been fighting lots of stuff and it has been impossible to find some time for it. Hopefully, I can get to it at the weekend :)

@brandtbucher
Copy link
Member Author

brandtbucher commented Feb 19, 2021

Gotcha. Yeah, I was referring to the next alpha, scheduled for 3/1. I thought maybe you might need a day or two between tagging and releasing or something.

@pablogsal
Copy link
Member

pablogsal commented Feb 19, 2021

I thought maybe you might need a day or two between tagging and releasing or something.

No, although is a multi-hour process, I normally do it on the same day as the release, at least for the alphas (assuming everything goes smoothly).

Copy link
Contributor

@willingc willingc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brandtbucher I did an initial pass and it looks good for alpha. I will look at it more closely this weekend.

@asottile
Copy link
Contributor

found a bit of an odd case while trying this out -- not sure if it's intentional:

x = 1

match x:
    case 1 as y if 0:
        print('unreachable')
print(f'{y=}')  # expect NameError

instead of NameError I get y=1

@pablogsal
Copy link
Member

found a bit of an odd case while trying this out -- not sure if it's intentional:

x = 1

match x:
    case 1 as y if 0:
        print('unreachable')
print(f'{y=}')  # expect NameError

instead of NameError I get y=1

IIRC I think that is covered in https://www.python.org/dev/peps/pep-0634/#side-effects-and-undefined-behavior, although the peephole could detect the branch and optimize it away.

@brandtbucher
Copy link
Member Author

brandtbucher commented Feb 20, 2021

Yeah, we're required to bind any names used by the guard before evaluating it (obviously). The current naive implementation accomplishes this by binding all names before hitting any guard. Strange example, but legal by the PEP.

I'm actually not sure the peephole/CFG could catch this (it can optimize out the body of the case, though, and it actually does here). Might be something for the AST optimizer.

Python/ceval.c Outdated
if (dummy == NULL) {
goto fail;
}
values = PyTuple_New(nkeys);
Copy link
Member

@pablogsal pablogsal Feb 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dangerous. You are preparing a tuple with nkeys but then you are filling it calling PyObject_CallFunctionObjArgs, which can execute arbitrary Python code. At this point, the tuple is tracked by the GC so code executed by PyObject_CallFunctionObjArgs could see the tuple half-initialized (the same if there is a gc pass). The same thing applies to anything done meanwhile the tuple is not ready that can call into arbitrary Python.

Copy link
Member Author

@brandtbucher brandtbucher Feb 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. So is filling it with None the right thing to do here, or can we cheat and just untrack/retrack?

Copy link
Member Author

@brandtbucher brandtbucher Feb 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, filling it with None can lead to problems (as we've seen before). So should we just untrack it temporarily?

I guess we could just fill a list and convert it to a tuple, too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I just went with list -> tuple for both. Let me know if you prefer something else.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option it to untrack the tuple after its creation and track it back when is ready. Be careful because some APIs can retrack it (like resizing the tuple). I would recommend to add some asserts to check that is untracked where is supposed to be if you decide to go this way.

Python/ceval.c Outdated
return NULL;
}
// So far so good:
PyObject *attrs = PyTuple_New(nargs + PyTuple_GET_SIZE(kwargs));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python/ceval.c Outdated
// to raise TypeErrors for repeated lookups. On failure, return NULL (with
// no error set). Use _PyErr_Occurred(tstate) to disambiguate.
assert(PyUnicode_CheckExact(name));
// XXX: Why doesn't PySet_CheckExact exist?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#24598

😉

@brandtbucher
Copy link
Member Author

I believe I have addressed all of the comments so far. If anyone still has additional feedback (or needs the weekend to review), please let me know. Otherwise, I'll plan on merging this Friday.

@pablogsal, should we hit it with the buildbots again?

@pablogsal pablogsal added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Feb 24, 2021
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @pablogsal for commit 61616fc 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Feb 24, 2021
@brandtbucher
Copy link
Member Author

brandtbucher commented Feb 25, 2021

The three failed jobs look unrelated to these changes; I see the same failures (with the same logs) on #24643.

@brandtbucher
Copy link
Member Author

Okay, I'm going to merge this. 🍾

Big thanks to everyone who took time to help out here!

@brandtbucher brandtbucher merged commit 145bf26 into python:master Feb 26, 2021
adorilson pushed a commit to adorilson/cpython that referenced this pull request Mar 13, 2021
Co-authored-by: Guido van Rossum <guido@python.org>
Co-authored-by: Talin <viridia@gmail.com>
Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
@brandtbucher brandtbucher deleted the patma branch July 21, 2022 20:20
Comment on lines +982 to +985
PyObject *attr = PyObject_GetAttr(subject, name);
if (attr == NULL && _PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Clear(tstate);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to use _PyObject_LookupAttr() here. See #106303.

Comment on lines +1037 to +1038
else if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Clear(tstate);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sprint type-feature A feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.