feat(detection-core): unique-declaration member-call binding (8.2 final gated round step 1-2)

x.method() with a variable receiver binds complete iff exactly one same-name
method declaration exists repository-wide; collisions stay a finite candidate
set (receiver_type_unknown) and module-level functions never bind. Authorized
by maintainer strategy-review 2026-10-31; gated by dev-pool FA non-regression.
This commit is contained in:
Marius Ciepluch
2026-10-31 07:10:36 +01:00
parent 1481bb33d7
commit dc2832564a
3 changed files with 73 additions and 0 deletions
@@ -239,7 +239,15 @@ def _type_receiver_targets(same_name: tuple[SymbolId, ...], type_name: str, arit
def _variable_receiver_targets(same_name: tuple[SymbolId, ...], arity: int | None) -> CallTargetSet:
# A variable receiver's type is unknown, but when exactly ONE method with the
# called name exists repository-wide, no second repository-defined target can
# exist, so the call binds complete (unique-declaration member-call binding).
# Two or more same-name declarations are a collision: they stay a finite
# candidate set, never a bare-name merge. A same-name module-level function is
# not a member-call target, so it neither binds nor collides here.
methods = tuple(symbol for symbol in same_name if symbol.enclosing_type is not None)
if len(methods) == 1:
return CallTargetSet(targets=methods, completeness=Completeness(is_complete=True))
narrowed = _arity_narrow(methods, arity)
if not narrowed:
return CallTargetSet(targets=(), completeness=Completeness(is_complete=False, reasons=("resolution:no_candidate",)))