Skip to content

fix(resolve): prefer a base CLASS for Python implements edges (#172)#180

Open
skakri wants to merge 1 commit into
mainfrom
fix/python-implements-pref
Open

fix(resolve): prefer a base CLASS for Python implements edges (#172)#180
skakri wants to merge 1 commit into
mainfrom
fix/python-implements-pref

Conversation

@skakri

@skakri skakri commented Jun 15, 2026

Copy link
Copy Markdown
Member

Fixes #172. Python base-class inheritance (class Sub(Base)) emits an implements edge to Base, which is a class — Python has no traits/interfaces. The resolver's implements preference was ["trait", "interface"], so a Python base never matched and the edge could mis-resolve to a same-named non-class or fall back ambiguously.

Fix

preferred_matches is now language-aware: for Python, implements prefers ["class", "object"]; Kotlin / TS / Rust are unchanged (["trait", "interface"]) — there implements / : I targets an interface, and a same-named class must not be preferred over it. The source language is already threaded into resolve_symbol (request.source_language), so this is a one-line branch in the existing preference table.

Verification

  • New resolve test python_implements_prefers_a_base_class_over_a_non_class: with a base class Base and a decoy same-named module-level function Base, the Python implements edge binds to the class.
  • e2e on a temp project: class Sub(Base) resolves implements → base.py::Base (class) at Syntactic confidence (was unresolved/ambiguous before).
  • Full rag-rat-core suite (482) green; fmt + clippy clean. Kotlin/TS implements tests unaffected (the branch is gated to Python).

Sibling of #174 (alias resolution, PR #179) — both Python resolver refinements deferred from #167. The remaining import x as m module-alias case is still out of scope (noted in #174).

Python base-class inheritance emits an `implements` edge to the base, which is a
CLASS (Python has no traits/interfaces). The resolver's `implements` preference
was `[trait, interface]`, so a Python base never matched the preference and could
mis-resolve to a same-named non-class or fall back ambiguously.

`preferred_matches` is now language-aware: for Python, `implements` prefers
`[class, object]`; Kotlin/TS/Rust are UNCHANGED (`implements`/`: I` targets an
interface, and a same-named class must not be preferred over it). Added a
resolve test (the base class is preferred over a decoy same-named function).
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

SCIP oracle — resolution report

Heuristic→compiler edge resolution per corpus. Δ compares resolved-after to the main baseline (only when the corpus profile + tool version match).

corpus tool edges resolved (heuristic → compiler) precision recall monikers Δ vs main
c-cjson scip-clang 3941 69.6% → 86.5% 89.1% 80.8% 911 +0.0pp
py-requests scip-python 1060 32.5% → 71.7% 89.9% 86.8% 292 +0.0pp
rust-semver rust-analyzer 1056 39.0% → 88.6% 79.6% 100.0% 78 +0.0pp

resolved = Exact/Syntactic + compiler upgrades + resolved-external, over edge candidates with a callee range. precision/recall are the oracle eval metrics.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acd8d90f99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// traits/interfaces — so prefer class-like kinds for Python (#172). Kept language-scoped so
// Kotlin/TS are UNCHANGED: there `implements`/`: I` targets an interface, and a same-named
// class must not be preferred over it.
"implements" if source_language == Some(Language::Python.as_str()) => &["class", "object"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid preferring foreign classes for Python bases

In mixed-language indexes this branch prefers any class/object symbol by kind only; preferred_matches does not check symbol.language, and the name buckets are repo-wide. When a Python base is external or otherwise not indexed as a Python class, but a TS/Kotlin/C++ class or Kotlin object with the same short name exists alongside another same-named non-class candidate, this new preferred set can resolve class Sub(Base) to the foreign symbol instead of leaving it unresolved. Please restrict the Python implements preference to Python symbols (or otherwise suppress cross-language candidates) when applying this branch.

Useful? React with 👍 / 👎.

// traits/interfaces — so prefer class-like kinds for Python (#172). Kept language-scoped so
// Kotlin/TS are UNCHANGED: there `implements`/`: I` targets an interface, and a same-named
// class must not be preferred over it.
"implements" if source_language == Some(Language::Python.as_str()) => &["class", "object"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid forcing call-style Python bases to classes

This preference also applies to every Python implements edge even when the superclass expression is a call, because python_edges emits implements for each positional superclass and python_type_head leaves a call expression to last_identifier_text (for example class Sub(Base()):). In that scenario, if the repo has both def Base(...) and a decoy class Base, the new preferred set resolves the inheritance edge to the class, whereas the actual base expression depends on the callable and the old resolver would leave the class/function collision ambiguous. Please avoid applying the class preference to call-shaped bases, or encode the expression shape so these dynamic bases do not bind to an unrelated class.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acd8d90f99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// traits/interfaces — so prefer class-like kinds for Python (#172). Kept language-scoped so
// Kotlin/TS are UNCHANGED: there `implements`/`: I` targets an interface, and a same-named
// class must not be preferred over it.
"implements" if source_language == Some(Language::Python.as_str()) => &["class", "object"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid preferring foreign classes for Python bases

In mixed-language indexes this branch prefers any class/object symbol by kind only; preferred_matches does not check symbol.language, and the name buckets are repo-wide. When a Python base is external or otherwise not indexed as a Python class, but a TS/Kotlin/C++ class or Kotlin object with the same short name exists alongside another same-named non-class candidate, this new preferred set can resolve class Sub(Base) to the foreign symbol instead of leaving it unresolved. Please restrict the Python implements preference to Python symbols (or otherwise suppress cross-language candidates) when applying this branch.

Useful? React with 👍 / 👎.

// traits/interfaces — so prefer class-like kinds for Python (#172). Kept language-scoped so
// Kotlin/TS are UNCHANGED: there `implements`/`: I` targets an interface, and a same-named
// class must not be preferred over it.
"implements" if source_language == Some(Language::Python.as_str()) => &["class", "object"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid forcing call-style Python bases to classes

This preference also applies to every Python implements edge even when the superclass expression is a call, because python_edges emits implements for each positional superclass and python_type_head leaves a call expression to last_identifier_text (for example class Sub(Base()):). In that scenario, if the repo has both def Base(...) and a decoy class Base, the new preferred set resolves the inheritance edge to the class, whereas the actual base expression depends on the callable and the old resolver would leave the class/function collision ambiguous. Please avoid applying the class preference to call-shaped bases, or encode the expression shape so these dynamic bases do not bind to an unrelated class.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown

🐰 Bencher Report

Branchfix/python-implements-pref
Testbedubuntu-latest

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
BenchmarkEstimated Cyclescycles x 1e6Instructionsinstructions x 1e6L1 Hitshits x 1e6LL Hitshits x 1e6RAM Hitshits x 1e3Total read+writereads/writes x 1e6
rag_pipeline::pipeline::index cargo_resolver:resolver_config()📈 view plot
⚠️ NO THRESHOLD
1,214.64 x 1e6📈 view plot
⚠️ NO THRESHOLD
801.18 x 1e6📈 view plot
⚠️ NO THRESHOLD
1,116.67 x 1e6📈 view plot
⚠️ NO THRESHOLD
17.42 x 1e6📈 view plot
⚠️ NO THRESHOLD
310.87 x 1e3📈 view plot
⚠️ NO THRESHOLD
1,134.40 x 1e6
rag_pipeline::pipeline::query_cold cargo_resolver:resolver_built_config()📈 view plot
⚠️ NO THRESHOLD
241.14 x 1e6📈 view plot
⚠️ NO THRESHOLD
154.71 x 1e6📈 view plot
⚠️ NO THRESHOLD
231.07 x 1e6📈 view plot
⚠️ NO THRESHOLD
1.94 x 1e6📈 view plot
⚠️ NO THRESHOLD
10.83 x 1e3📈 view plot
⚠️ NO THRESHOLD
233.02 x 1e6
rag_pipeline::pipeline::query_warm cargo_resolver:resolver_index()📈 view plot
⚠️ NO THRESHOLD
232.81 x 1e6📈 view plot
⚠️ NO THRESHOLD
149.12 x 1e6📈 view plot
⚠️ NO THRESHOLD
223.16 x 1e6📈 view plot
⚠️ NO THRESHOLD
1.86 x 1e6📈 view plot
⚠️ NO THRESHOLD
10.10 x 1e3📈 view plot
⚠️ NO THRESHOLD
225.03 x 1e6
🐰 View full continuous benchmarking report in Bencher

@github-actions

Copy link
Copy Markdown

🐰 Bencher Report

Branchfix/python-implements-pref
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
seconds (s)
(Result Δ%)
Upper Boundary
seconds (s)
(Limit %)
index_time/full_rebuild_cargo📈 view plot
🚷 view threshold
5.03 s
(+34.17%)Baseline: 3.75 s
5.79 s
(86.91%)
🐰 View full continuous benchmarking report in Bencher

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python Implements edges: resolver prefers trait/interface, not class

1 participant