Follow-up from the review of #722.
#722's tie arm exists to make one thing impossible — "the engine can then never land a resolution on a different node than extraction chose". It does not fully deliver that, and the test written to pin it cannot detect the gap.
The gap
The len(owners) > 1 arm picks enclosingCallable when it is any tied owner, then upgradeExistingCall claims that owner's same-line same-name stub — regardless of which owner authored the fact currently being applied. When two tied owners call the same name on different types, the first fact applied retargets the method's stub to the other owner's target, and the method's own correct target is then unreachable because the edge is no longer claimable.
Repro
Core/Engine.cs with class Engine { Fire, Halt }, Core/Other.cs with class Other { Fire }, and Use/Rig.cs:
private Engine motor; private Other pal;
public int Level { get { motor.Fire(); return 7; } } public void Busy() { pal.Fire(); }
Observed at 6be528ef:
Use/Rig.cs::Rig.Busy -> Core/Engine.cs::Engine.Fire line=5 conf=0.95 origin=ast_resolved
Use/Rig.cs::Rig.Level -> unresolved::*.Fire
Busy calls pal.Fire(), i.e. Other.Fire. It carries a confident 0.95 edge to a type it never calls, and its real call is lost. Expected: Busy -> Other.Fire, with the property's own site either resolved to Engine.Fire or left untouched.
Why the existing pin misses it
TestCSharp_SameNameTieMethodKeepsOwnCall uses a fixture where both owners call the same target, so the assertion passes no matter which fact produced the edge. The test is not wrong, it just cannot discriminate. A fixture with two different targets is what is needed.
Scope
This is not a regression — 903b520b behaves identically, because containment picked the method there too. Filing it because the tie arm was introduced specifically to close this class, and because the PR body states the stronger guarantee. Either the arm should carry the authored fact's owner through to the claim, or the body's claim should be narrowed to what the arm actually provides.
Related shape from the same review, same arm: when a property and a method both call a same-named method on one shared line, both call facts hit the tie arm and both resolve onto the method, so the property's own call is not independently resolved. Also not a regression, and also not what the body's framing implies.
Follow-up from the review of #722.
#722's tie arm exists to make one thing impossible — "the engine can then never land a resolution on a different node than extraction chose". It does not fully deliver that, and the test written to pin it cannot detect the gap.
The gap
The
len(owners) > 1arm picksenclosingCallablewhen it is any tied owner, thenupgradeExistingCallclaims that owner's same-line same-name stub — regardless of which owner authored the fact currently being applied. When two tied owners call the same name on different types, the first fact applied retargets the method's stub to the other owner's target, and the method's own correct target is then unreachable because the edge is no longer claimable.Repro
Core/Engine.cswithclass Engine { Fire, Halt },Core/Other.cswithclass Other { Fire }, andUse/Rig.cs:Observed at
6be528ef:Busycallspal.Fire(), i.e.Other.Fire. It carries a confident 0.95 edge to a type it never calls, and its real call is lost. Expected:Busy -> Other.Fire, with the property's own site either resolved toEngine.Fireor left untouched.Why the existing pin misses it
TestCSharp_SameNameTieMethodKeepsOwnCalluses a fixture where both owners call the same target, so the assertion passes no matter which fact produced the edge. The test is not wrong, it just cannot discriminate. A fixture with two different targets is what is needed.Scope
This is not a regression —
903b520bbehaves identically, because containment picked the method there too. Filing it because the tie arm was introduced specifically to close this class, and because the PR body states the stronger guarantee. Either the arm should carry the authored fact's owner through to the claim, or the body's claim should be narrowed to what the arm actually provides.Related shape from the same review, same arm: when a property and a method both call a same-named method on one shared line, both call facts hit the tie arm and both resolve onto the method, so the property's own call is not independently resolved. Also not a regression, and also not what the body's framing implies.