mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-24 00:51:53 +00:00
fix(cpp): suppress receiver-bound CALLS when default-arg overloads collide (U4)
ISO C++ rejects 's.f(1)' as ambiguous when both 'void f(int)' and 'void f(int, int = 0)' are declared on S. The previous resolver returned the first viable candidate via pickOverload's fallback. Extended isOverloadAmbiguousAfterNormalization to take an optional argCount: when provided, the predicate compares only the first argCount slots of each candidate's parameterTypes. Candidates whose declared-prefix matches up to argCount are treated as ambiguous because default arguments make all of them equally viable for the call. Without argCount, behavior is unchanged (the original int/long normalization-collapse contract, full-length equality required). pickOverload now passes site.arity so default-arg ambiguity fires. Test: cpp-overload-default-arg-ambiguous fixture. s.f(1) where S has f(int) and f(int, int = 0) asserts exactly .toBe(0) CALLS edges. Passes under both REGISTRY_PRIMARY_CPP=1 and =0. All 2114 resolver integration tests pass; all 148 cpp tests pass under both modes.
This commit is contained in:
parent
6a1e2a9ed0
commit
f543339a4f
6 changed files with 63 additions and 3 deletions
|
|
@ -119,17 +119,32 @@ export function narrowOverloadCandidates(
|
|||
*/
|
||||
export function isOverloadAmbiguousAfterNormalization(
|
||||
candidates: readonly SymbolDefinition[],
|
||||
argCount?: number,
|
||||
): boolean {
|
||||
if (candidates.length < 2) return false;
|
||||
const first = candidates[0].parameterTypes;
|
||||
if (first === undefined) return false;
|
||||
// When argCount is provided, compare only the first `argCount` slots —
|
||||
// this catches default-argument ambiguity: `void f(int); void f(int, int = 0);`
|
||||
// called with `f(1)` (argCount=1) leaves both candidates viable because
|
||||
// default args make them arity-compatible, and their first slot is
|
||||
// identical even though full parameterTypes lengths differ.
|
||||
// Without argCount, fall back to full-sequence comparison (the original
|
||||
// int/long normalization-collapse case).
|
||||
const compareUpTo = argCount !== undefined ? argCount : first.length;
|
||||
if (compareUpTo === 0) return false;
|
||||
if (first.length < compareUpTo) return false;
|
||||
for (let i = 1; i < candidates.length; i++) {
|
||||
const p = candidates[i].parameterTypes;
|
||||
if (p === undefined) return false;
|
||||
if (p.length !== first.length) return false;
|
||||
for (let j = 0; j < p.length; j++) {
|
||||
if (p.length < compareUpTo) return false;
|
||||
for (let j = 0; j < compareUpTo; j++) {
|
||||
if (p[j] !== first[j]) return false;
|
||||
}
|
||||
// When argCount is NOT provided, also require length equality so
|
||||
// distinct-arity candidates that happen to share a prefix don't
|
||||
// collapse to ambiguous (preserves the original int/long contract).
|
||||
if (argCount === undefined && p.length !== first.length) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -549,7 +549,7 @@ function pickOverload(
|
|||
// The graph schema has no ambiguous-target edge model, so emitting one
|
||||
// would arbitrarily pick a candidate and lie about the call's target.
|
||||
// PR #1520 review follow-up plan U2 / Claude review Finding 5.
|
||||
if (isOverloadAmbiguousAfterNormalization(candidates)) return OVERLOAD_AMBIGUOUS;
|
||||
if (isOverloadAmbiguousAfterNormalization(candidates, site.arity)) return OVERLOAD_AMBIGUOUS;
|
||||
return candidates[0] ?? overloads[0];
|
||||
}
|
||||
|
||||
|
|
|
|||
6
gitnexus/test/fixtures/lang-resolution/cpp-overload-default-arg-ambiguous/caller.cpp
vendored
Normal file
6
gitnexus/test/fixtures/lang-resolution/cpp-overload-default-arg-ambiguous/caller.cpp
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "service.h"
|
||||
|
||||
void run() {
|
||||
S s;
|
||||
s.f(1);
|
||||
}
|
||||
4
gitnexus/test/fixtures/lang-resolution/cpp-overload-default-arg-ambiguous/service.cpp
vendored
Normal file
4
gitnexus/test/fixtures/lang-resolution/cpp-overload-default-arg-ambiguous/service.cpp
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#include "service.h"
|
||||
|
||||
void S::f(int) {}
|
||||
void S::f(int, int) {}
|
||||
7
gitnexus/test/fixtures/lang-resolution/cpp-overload-default-arg-ambiguous/service.h
vendored
Normal file
7
gitnexus/test/fixtures/lang-resolution/cpp-overload-default-arg-ambiguous/service.h
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
class S {
|
||||
public:
|
||||
void f(int);
|
||||
void f(int, int = 0);
|
||||
};
|
||||
|
|
@ -1854,3 +1854,31 @@ describe('C++ namespace-qualified call is not a super receiver', () => {
|
|||
expect(getInstanceCalls[0].targetFilePath).toContain('singleton.h');
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// U4 (follow-up plan 2026-05-13-001): default-argument overload ambiguity.
|
||||
// `void f(int); void f(int, int = 0); f(1);` is ambiguous per ISO C++. The
|
||||
// OVERLOAD_AMBIGUOUS sentinel from plan 2026-05-12-002 U2 should detect
|
||||
// this case via isOverloadAmbiguousAfterNormalization.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('C++ default-argument overload ambiguity', () => {
|
||||
let result: PipelineResult;
|
||||
|
||||
beforeAll(async () => {
|
||||
result = await runPipelineFromRepo(
|
||||
path.join(FIXTURES, 'cpp-overload-default-arg-ambiguous'),
|
||||
() => {},
|
||||
);
|
||||
}, 60000);
|
||||
|
||||
it('s.f(1) emits zero CALLS edges when f(int) and f(int, int=0) both match', () => {
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
const fCalls = calls.filter((c) => c.source === 'run' && c.target === 'f');
|
||||
// Exact .toBe(0): count=1 means arbitrary pick (the bug); count=2+ would
|
||||
// require an ambiguous-target edge model GitNexus does not have. The
|
||||
// resolver must suppress entirely. Standard C++ rejects the call as
|
||||
// ambiguous (GCC/Clang both diagnose).
|
||||
expect(fCalls.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue