Skip to content

Revert class lookup#7306

Merged
youknowone merged 2 commits intoRustPython:mainfrom
youknowone:skip-class
Mar 2, 2026
Merged

Revert class lookup#7306
youknowone merged 2 commits intoRustPython:mainfrom
youknowone:skip-class

Conversation

@youknowone
Copy link
Member

@youknowone youknowone commented Mar 2, 2026

wrong optimization

Summary by CodeRabbit

  • Improvements
    • Made isinstance/issubclass checks more consistent by always resolving an object’s class via attribute lookup. This reduces edge-case inconsistencies for objects with custom attribute access or modified class mechanisms, improving reliability and predictability when checking types across dynamic or altered class hierarchies.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 2, 2026

📝 Walkthrough

Walkthrough

Removed has_standard_getattro() from PyObject and simplified isinstance/issubclass control flow to always resolve __class__ via vm.get_attribute_opt("__class__"), removing the prior pre-check branch and helper.

Changes

Cohort / File(s) Summary
Object protocol
crates/vm/src/protocol/object.rs
Removed fn has_standard_getattro(&self) -> bool. Reworked object_isinstance/object_issubclass flow to drop the data-descriptor/slot pre-check and perform a direct __class__ attribute lookup (vm.get_attribute_opt) followed by subtype/abstract_issubclass checks. Minor import formatting adjustments.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant PyObject
  participant VM
  participant TypeUtils

  Caller->>PyObject: object_isinstance(obj, cls)
  alt cls is a type
    PyObject->>TypeUtils: subtype check (is subclass)
    TypeUtils-->>PyObject: result
  else cls is not a type
    PyObject->>VM: get_attribute_opt(obj, "__class__")
    VM-->>PyObject: class_obj or None
    alt class_obj found
      PyObject->>TypeUtils: abstract_issubclass(class_obj, cls)
      TypeUtils-->>PyObject: result
    else not found
      PyObject-->>Caller: return False
    end
  end
  PyObject-->>Caller: final bool
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰
I hopped through code and found the trace,
One helper gone, a cleaner place.
No early hop, just ask and see,
The VM reveals what class will be.
A tiny change, a lighter pace.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Revert class lookup' accurately describes the main change—removing the has_standard_getattro() helper and simplifying object_isinstance class lookup logic.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@youknowone youknowone marked this pull request as ready for review March 2, 2026 03:40
The optimization to skip __class__ lookup based on getattro check
was incorrect: a class can override __class__ as a property while
still using standard __getattribute__. Revert to always performing
the lookup, matching CPython's object_isinstance behavior.
@youknowone youknowone changed the title Skip __class__ lookup in object_isinstance when safe Revert class lookup Mar 2, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/vm/src/protocol/object.rs (1)

579-607: Add focused regression tests for __class__-driven isinstance semantics.

Given this revert fixes a prior optimization, please add coverage for objects overriding __getattribute__/__class__ to prevent future regressions in this path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm/src/protocol/object.rs` around lines 579 - 607, Add focused
regression tests that exercise object_isinstance's fallback path when instances
override __getattribute__ or __class__; create tests that call isinstance(obj,
SomeType) where obj provides a custom __getattribute__ and a dynamic __class__
attribute so the branch that uses vm.get_attribute_opt(self.to_owned(),
identifier!(vm, __class__)) and then calls abstract_issubclass or
PyTypeRef::try_from_object is executed; specifically target the code paths in
object_isinstance (the branch guarded by let Some(i_cls) =
vm.get_attribute_opt(...)) and ensure both the i_cls Type conversion
(PyTypeRef::try_from_object) and the abstract_issubclass call are covered to
detect regressions of the reverted optimization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/vm/src/protocol/object.rs`:
- Around line 579-607: Add focused regression tests that exercise
object_isinstance's fallback path when instances override __getattribute__ or
__class__; create tests that call isinstance(obj, SomeType) where obj provides a
custom __getattribute__ and a dynamic __class__ attribute so the branch that
uses vm.get_attribute_opt(self.to_owned(), identifier!(vm, __class__)) and then
calls abstract_issubclass or PyTypeRef::try_from_object is executed;
specifically target the code paths in object_isinstance (the branch guarded by
let Some(i_cls) = vm.get_attribute_opt(...)) and ensure both the i_cls Type
conversion (PyTypeRef::try_from_object) and the abstract_issubclass call are
covered to detect regressions of the reverted optimization.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 863fd73 and 864bf57.

📒 Files selected for processing (1)
  • crates/vm/src/protocol/object.rs

@youknowone youknowone merged commit 3865fdb into RustPython:main Mar 2, 2026
21 of 24 checks passed
@youknowone youknowone deleted the skip-class branch March 2, 2026 10:41
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.

1 participant