docs(php): document '...' vs 'params' variadic-marker asymmetry (U5)

The shared narrowOverloadCandidates pass in scope-resolution/passes/
overload-narrowing.ts checks for 'params'/'params ' as the variadic
marker - the C# 'params' keyword convention. PHP uses '...' instead,
matching its source-language syntax. The discrepancy is harmless in
practice because PHP variadic methods set parameterCount=undefined,
which skips the 'max !== undefined && argCount > max' gate that hosts
the 'params' check entirely - so the C# branch is dead code for PHP.

Document the asymmetry at both sites with cross-references so a future
contributor reading either file lands on the full picture:

- overload-narrowing.ts:48 area: explains the 'params' branch is C#-
  specific and warns that adding new markers requires auditing each
  adapter's arity-metadata.ts.
- languages/php/arity-metadata.ts:46 area: explains PHP uses '...'
  intentionally and that the shared pass's 'params' branch is dead
  code for PHP because of the parameterCount=undefined setting.

No behavior change. Existing PHP variadic-resolution tests already
exercise the live '...' path.
This commit is contained in:
Gergo Magyar 2026-05-12 12:39:02 +01:00
parent e90f77cb2a
commit ea04c5ee52
2 changed files with 21 additions and 0 deletions

View file

@ -43,6 +43,17 @@ export function computePhpArityMetadata(fnNode: SyntaxNode): PhpArityMetadata {
}
if (p.type !== null) types.push(p.type);
}
// PHP variadic marker convention: append the literal '...' string to
// `parameterTypes`. This is intentionally DIFFERENT from C#, which uses
// the literal 'params' (its source-language keyword). The shared
// `narrowOverloadCandidates` pass in `scope-resolution/passes/overload-
// narrowing.ts` checks for the C# 'params' marker — that branch is
// dead code for PHP because PHP variadic methods set `parameterCount
// = undefined` (see line below), which skips the `max !== undefined`
// gate that hosts the 'params' check. PHP's actual variadic-aware
// arity logic lives in `phpArityCompatibility` (arity.ts) and now
// also in `phpEmitUnresolvedReceiverEdges` (scope-resolver.ts), both
// of which check `'...'`. Finding 9 of PR #1497 adversarial review.
if (hasVariadic) types.push('...');
const total = params.length;

View file

@ -43,6 +43,16 @@ export function narrowOverloadCandidates(
const max = d.parameterCount;
const min = d.requiredParameterCount;
if (max !== undefined && argCount > max) {
// Variadic marker check is C#-specific (the 'params' keyword).
// Other languages use their own marker — PHP uses '...' (see
// `languages/php/arity-metadata.ts:46`), Python uses '*args'-
// shaped metadata that lives outside `parameterTypes` entirely.
// This branch is dead code for those languages because they
// set `parameterCount = undefined` for variadic functions,
// which keeps `max` undefined and skips this check entirely.
// Adding new variadic markers here changes behavior for those
// other languages too — don't extend without auditing each
// adapter's `arity-metadata.ts`. Finding 9 of PR #1497.
const variadic =
d.parameterTypes !== undefined &&
d.parameterTypes.some((t) => t === 'params' || t.startsWith('params '));