diff --git a/gitnexus/test/fixtures/lang-resolution/dart-callable-alternatives/app.dart b/gitnexus/test/fixtures/lang-resolution/dart-callable-alternatives/app.dart index f07d2c009..3ea5767a6 100644 --- a/gitnexus/test/fixtures/lang-resolution/dart-callable-alternatives/app.dart +++ b/gitnexus/test/fixtures/lang-resolution/dart-callable-alternatives/app.dart @@ -7,6 +7,13 @@ void ifNull(void Function()? override) { run(); } +void runLeft() {} + +void callableLeft(void Function() fallback) { + final run = runLeft ?? fallback; + run(); +} + void conditional(bool fast) { final run = fast ? runThen : runElse; run(); diff --git a/gitnexus/test/fixtures/lang-resolution/kotlin-callable-alternatives/App.kt b/gitnexus/test/fixtures/lang-resolution/kotlin-callable-alternatives/App.kt index b7b406a85..ccccd8c16 100644 --- a/gitnexus/test/fixtures/lang-resolution/kotlin-callable-alternatives/App.kt +++ b/gitnexus/test/fixtures/lang-resolution/kotlin-callable-alternatives/App.kt @@ -7,6 +7,13 @@ fun elvis(override: (() -> Unit)?) { run() } +fun runLeft() {} + +fun callableLeft(fallback: () -> Unit) { + val run = ::runLeft ?: fallback + run() +} + fun ifExpression(fast: Boolean) { val run = if (fast) ::runThen else ::runElse run() diff --git a/gitnexus/test/fixtures/lang-resolution/python-callable-alternatives/app.py b/gitnexus/test/fixtures/lang-resolution/python-callable-alternatives/app.py index 46180c9ba..5c198c1ae 100644 --- a/gitnexus/test/fixtures/lang-resolution/python-callable-alternatives/app.py +++ b/gitnexus/test/fixtures/lang-resolution/python-callable-alternatives/app.py @@ -18,6 +18,15 @@ def run_or_else(): pass +def run_left(): + pass + + +def callable_left(fallback): + run = run_left or fallback + run() + + def logical_or(override): run = override or run_sweep run() diff --git a/gitnexus/test/fixtures/lang-resolution/swift-callable-alternatives/App.swift b/gitnexus/test/fixtures/lang-resolution/swift-callable-alternatives/App.swift index bf5d0dab2..fd22a96a8 100644 --- a/gitnexus/test/fixtures/lang-resolution/swift-callable-alternatives/App.swift +++ b/gitnexus/test/fixtures/lang-resolution/swift-callable-alternatives/App.swift @@ -7,6 +7,13 @@ func nilCoalescing(override: (() -> Void)?) { run() } +func runLeft() {} + +func callableLeft(fallback: @escaping () -> Void) { + let run = runLeft ?? fallback + run() +} + func ternary(fast: Bool) { let run = fast ? runThen : runElse run() diff --git a/gitnexus/test/fixtures/python-captures-golden/expected-captures.json b/gitnexus/test/fixtures/python-captures-golden/expected-captures.json index 9ea10da78..78827ffdd 100644 --- a/gitnexus/test/fixtures/python-captures-golden/expected-captures.json +++ b/gitnexus/test/fixtures/python-captures-golden/expected-captures.json @@ -96,8 +96,8 @@ "digest": "9c7f1c54a9b0ba3bfa4410e1843bf5edb570777789ee659a00d7dd6771f3670f" }, "python-callable-alternatives/app.py": { - "captureGroups": 35, - "digest": "e35b269b282c3955c4a196c6ecc2292c82bbba1c9579590cc970fe2ddee6f3c5" + "captureGroups": 85, + "digest": "d5fc223832a33ff701f09b00174bdf1e127063aae9bdead0e5d242e8bd8e12ef" }, "python-calls/one.py": { "captureGroups": 4, diff --git a/gitnexus/test/fixtures/swift-captures-golden/expected-captures.json b/gitnexus/test/fixtures/swift-captures-golden/expected-captures.json index 4522da5ff..d4c313237 100644 --- a/gitnexus/test/fixtures/swift-captures-golden/expected-captures.json +++ b/gitnexus/test/fixtures/swift-captures-golden/expected-captures.json @@ -24,8 +24,8 @@ "digest": "f192ae885ea3de848f3b93acf7672d91b0118800cb0c6513628a6c09c26fadbf" }, "swift-callable-alternatives/App.swift": { - "captureGroups": 25, - "digest": "0d76e7d11637a41550666de93a390861d15a0a26edf9c49af19fbd625a3ba1f3" + "captureGroups": 36, + "digest": "3720e42c769ba4f6fa2becfe55f10109e170e8ac274ce24e69b04b7b23a25a8a" }, "swift-child-extends-parent/Sources/App.swift": { "captureGroups": 11, diff --git a/gitnexus/test/integration/resolvers/callable-alternatives-providers.test.ts b/gitnexus/test/integration/resolvers/callable-alternatives-providers.test.ts index 7e619d5ed..b8625f1ef 100644 --- a/gitnexus/test/integration/resolvers/callable-alternatives-providers.test.ts +++ b/gitnexus/test/integration/resolvers/callable-alternatives-providers.test.ts @@ -40,6 +40,12 @@ describe('Python callable chosen by `or` / `and` / `x if c else y`', () => { expect(callsOf(result)).toContain('logical_or → run_sweep'); }); + // The `override or fn` case above resolves only its RIGHT operand, so it + // would still pass if the fan-out kept just the last branch. + it('`fn or fallback` reaches fn through the LEFT operand', () => { + expect(callsOf(result)).toContain('callable_left → run_left'); + }); + it('`f if c else g` reaches both branches', () => { expect(callsOf(result)).toEqual( expect.arrayContaining(['ternary → run_then', 'ternary → run_else']), @@ -75,6 +81,10 @@ describe('Kotlin callable chosen by `?:` / `if` expression', () => { expect(callsOf(result)).toContain('elvis → runSweep'); }); + it('`::fn ?: fallback` reaches fn through the LEFT operand', () => { + expect(callsOf(result)).toContain('callableLeft → runLeft'); + }); + it('`if (c) ::f else ::g` reaches both branches', () => { expect(callsOf(result)).toEqual( expect.arrayContaining(['ifExpression → runThen', 'ifExpression → runElse']), @@ -104,6 +114,10 @@ describe('Swift callable chosen by `??` / `?:`', () => { expect(callsOf(result)).toContain('nilCoalescing → runSweep'); }); + it('`fn ?? fallback` reaches fn through the LEFT operand', () => { + expect(callsOf(result)).toContain('callableLeft → runLeft'); + }); + it('`c ? f : g` reaches both branches', () => { expect(callsOf(result)).toEqual( expect.arrayContaining(['ternary → runThen', 'ternary → runElse']), @@ -121,6 +135,10 @@ describe('Dart callable chosen by `??` / `?:`', () => { expect(callsOf(result)).toContain('ifNull → runSweep'); }); + it('`fn ?? fallback` reaches fn through the LEFT operand', () => { + expect(callsOf(result)).toContain('callableLeft → runLeft'); + }); + it('`c ? f : g` reaches both branches', () => { expect(callsOf(result)).toEqual( expect.arrayContaining(['conditional → runThen', 'conditional → runElse']),