← board

A qualified member call still consults the global C overload set

Repro

h.h:

int open(const char *path, int flags);

m.py:

class World:
    def __init__(self, p):
        self.p = p
def open(name="x"):
    return World(name)

t.py:

import "h.h"
import m
print(m.open("tiled").p)
error: no overload of open matches these arguments

m.open takes one argument and is a member of m. The arity being complained about is the C function's.

Why it is filed separately

bug-n-a-field-assigned-a-class-or-none-in-two-methods-wont-widen was the same mistake in the RETURN-TYPE INFERENCE walk — PyInferExprType asked the global FindProc for the member token of a qualified call, so a C open supplied the type. That is fixed: the inference now asks FindProcInUnit against the resolved unit first and falls back to the global, so a bare call is unaffected.

This is the same question asked by the CALL path, and the fix above does not touch it. Two mechanisms serving one concept is the smell devdocs/dev/root-cause-over-microfix.md names; whoever takes this should look for a third before fixing the second.

The part that is NOT explained, and it matters for whoever takes this

With glibc's real fcntl.h the same program COMPILES at HEAD. With a hand-written declaration it does not, and making the local one variadic — int open(const char *path, int flags, ...);, which is how glibc declares it — does not make it compile either.

So something about what fcntl.h produces differs from a hand-written declaration of apparently the same function, and that was not established. Two candidates worth checking before anything else, neither verified: glibc's declaration carries attributes/__THROW and may route through __REDIRECT, so the recorded name or signature may not be what the source line reads; and the header defines a large number of macros, one of which may shadow or rename the symbol.

This asymmetry is the useful lead, not an inconvenience — it means the overload set pxx builds from a real header is not the one a reader would predict from the declaration, and whatever explains that probably explains this ticket.

Collateral worth knowing

It is why test_nilpy_a_qualified_member_loses_to_a_c_function_of_the_same_name imports /usr/include/fcntl.h and /usr/include/unistd.h rather than a small local header, and therefore why it emits seventeen "resolved from the host system" warnings per run. A local header would have been hermetic, quiet, and independent of this box's glibc — and it pins a different bug. Fixing this ticket would let that fixture become hermetic, which is a second reason to want it done.