Skip to content

Python: reintroduce instance-attribute type-tracking without the classInstanceTracker blow-up#22097

Draft
Copilot wants to merge 3 commits into
mainfrom
copilot/reintroduce-functionality
Draft

Python: reintroduce instance-attribute type-tracking without the classInstanceTracker blow-up#22097
Copilot wants to merge 3 commits into
mainfrom
copilot/reintroduce-functionality

Conversation

Copilot AI commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

#22092 disabled the instanceFieldStep disjunct of TypeTrackingInput::levelStepCall because it identified instances via classInstanceTracker — a full type-tracker run — from inside levelStepCall, creating a mutual recursion that caused catastrophic slowdowns on OOP-heavy code bases (e.g. mypy, dask). This reintroduces the same flow (a value stored on self.attr in a method, read later as instance.attr) via a cheaper instance-identification strategy.

Change

  • instanceAttrRead now identifies the instance using local flow (getALocalSource(), purely simpleLocalFlowStep-based) from a constructor call resolved by resolveClassCall/classTracker, instead of classInstanceTracker. This drops the recursive dependency to the same call-graph machinery already used by the un-disabled inheritedFieldStep.
  • instanceFieldStep is otherwise unchanged (same levelStepCall shape, same getADirectSuperclass* relation).
  • Updated QLDoc + change note.
private predicate instanceAttrRead(Class cls, string attr, DataFlowPublic::AttrRead read) {
  exists(DataFlowPublic::CallCfgNode construction |
    DataFlowDispatch::resolveClassCall(construction.asCfgNode(), cls) and
    read.getObject().getALocalSource() = construction
  ) and
  read.mayHaveAttributeName(attr)
}

Trade-off

Precision drops for instances that flow across a call/return before being read — these are no longer covered, since the instance is now tracked only by local flow rather than a dedicated instance type-tracker.

Notes for reviewers

  • The 4 external-instance-read results previously produced by instanceFieldStep are reproduced; typetracking, dataflow, callgraph, ApiGraphs, and taint library tests pass.
  • The performance improvement is argued from the dependency structure (classTracker + local flow vs. classInstanceTracker); it was not measured against mypy/dask in this environment, so confirming the blow-up is resolved on those code bases is worth doing before merge.

@owen-mc

owen-mc commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@copilot add a case to one of the existing tests with a MISSING tag which demonstrates the shortcomings of the approach taken in this PR.

Copilot AI commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot add a case to one of the existing tests with a MISSING tag which demonstrates the shortcomings of the approach taken in this PR.

Added a MISSING case to attribute_tests.py (in the "attribute set in method" section). It defines a factory make_my_class2() returning a MyClass2(), then reads .foo on the returned instance; since instanceFieldStep now identifies instances only by local flow from the constructor call, the value stored on self.foo is no longer seen once the instance crosses the return boundary, so the read is annotated # $ MISSING: tracked. The typetracking tests still pass.

Copilot AI requested a review from owen-mc June 30, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants