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-36974: Make tp_call=PyVectorcall_Call work for inherited types #13699

Merged
merged 2 commits into from
Jun 2, 2019

Conversation

encukou
Copy link
Member

@encukou encukou commented May 31, 2019

When inheriting a heap subclass from a vectorcall class that sets .tp_call=PyVectorcall_Call (as recommended), the subclass does not inherit _Py_TPFLAGS_HAVE_VECTORCALL, and thus PyVectorcall_Call does not work for it.

This attempts to solve the issue by:

  • always inheriting tp_vectorcall_offset unless tp_call is overridden in the subclass
  • inheriting _Py_TPFLAGS_HAVE_VECTORCALL for static types, unless tp_call is overridden
  • making PyVectorcall_Call ignore _Py_TPFLAGS_HAVE_VECTORCALL

This means it'll be ever more important to only call PyVectorcall_Call on classes that support vectorcall. In PyVectorcall_Call's intended role as tp_call filler, that's not a problem.

cc @jdemeyer (not Mark, as he seemed to want to stay out of subclassing – but he's nosy on the issue)

https://bugs.python.org/issue36974

@jdemeyer
Copy link
Contributor

jdemeyer commented Jun 1, 2019

I don't have much time to look into this, but your idea sounds reasonable.

@encukou encukou merged commit fb9423f into python:master Jun 2, 2019
@encukou encukou deleted the pep590inherit branch June 2, 2019 22:11
encukou added a commit to jdemeyer/cpython that referenced this pull request Jun 2, 2019
This is not described in detail in PEP 590;
see python#13699
for the practical issue.
@jdemeyer
Copy link
Contributor

jdemeyer commented Jun 3, 2019

Reviewing this now after the fact... looks mostly good to me.

One potential issue: it is safer to inherit tp_vectorcall_offset unconditionally, even if tp_call is overridden. This allows a custom tp_call implementation falling back to the tp_call of the base class. Essentially the C equivalent of

def __call__(self, *args, **kwds):
    # do something interesting here
    return super().__call__(*args, **kwds)

Do you agree?

And one minor detail: in _PyVectorcall_Function(), the check Py_TYPE(callable)->tp_call is an assertion assert(PyCallable_Check(callable)); so I wonder why you made it a real check here.

@encukou
Copy link
Member Author

encukou commented Jun 3, 2019

it is safer to inherit tp_vectorcall_offset unconditionally

Yes, that's a good point. Do you want to write the test for that?

in _PyVectorcall_Function(), the check Py_TYPE(callable)->tp_call is an assertion assert(PyCallable_Check(callable));

Ah, that's a remnant of my investigations that I didn't adjust back to match _PyVectorcall_Function again. I don't feel strongly about this.

DinoV pushed a commit to DinoV/cpython that referenced this pull request Jan 14, 2020
…ythonGH-13699)

When inheriting a heap subclass from a vectorcall class that sets
`.tp_call=PyVectorcall_Call` (as recommended in PEP 590), the subclass does
not inherit `_Py_TPFLAGS_HAVE_VECTORCALL`, and thus `PyVectorcall_Call` does
not work for it.

This attempts to solve the issue by:
* always inheriting `tp_vectorcall_offset` unless `tp_call` is overridden
  in the subclass
* inheriting _Py_TPFLAGS_HAVE_VECTORCALL for static types, unless `tp_call`
  is overridden
* making `PyVectorcall_Call` ignore `_Py_TPFLAGS_HAVE_VECTORCALL`

This means it'll be ever more important to only call `PyVectorcall_Call`
on classes that support vectorcall. In `PyVectorcall_Call`'s intended role
as `tp_call` filler, that's not a problem.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants