Follow the shape-vector provenance walk through user-function returns (wala/ML#706)#554
Conversation
…wala#706). The walk added for wala#703 was intraprocedural, so a shape list produced by a user helper (the BERT/ALBERT `get_shape_list` pattern) stopped it at the helper's invoke. `getShapesOfShapeVector` now resolves the invoke's call-graph targets and walks every callee's returned value through the same chain recognition, unioning across callees and returns and falling back to ⊤ when any return doesn't resolve. No explicit parameter-to-argument mapping is needed: the callee parameter's interprocedural points-to set already holds the caller's allocation, so the `.shape` base case resolves across the boundary. A visited set threaded through the recursion guards recursive helpers. `isShapeVectorChain` mirrors the interprocedural case (and now takes the builder), so the legacy pin's skip case and `Reshape`'s ⊤-guard recognize the helper form; without it, the pin unioned ⊤ into the precise result and one context leaked the input tensor's shape. `testShapeHelperSlice` pins the precise `(5, 6)` for `get_shape(t)[-2:]`; `testShapeHelperSliceVar` combines the hop with wala#704's negated variable bound (`get_shape(t)[-k:]`), structurally NLPGNN's `einsum_via_matmul` shape read. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019qw3CqL43aLvPaj1xkWQ2m
There was a problem hiding this comment.
Pull request overview
This PR extends TensorFlow shape-vector provenance in the Python tensor analysis so that shape lists produced by user helper functions (e.g., get_shape_list-style helpers) are followed interprocedurally through callee returns, preventing premature ⊤ results and avoiding reshape fallback leaks when the helper form is involved.
Changes:
- Add interprocedural handling to
TensorGenerator.getShapesOfShapeVectorby walking call-graph targets and analyzing each callee’s returned value(s), with recursion guarding via a visited set. - Extend
TensorGenerator.isShapeVectorChainto mirror the interprocedural helper-return case (now requiring the call-graph builder). - Add two new Python fixtures and corresponding JUnit tests to cover helper-return slicing with both literal and negated-variable slice bounds.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| com.ibm.wala.cast.python.ml/source/com/ibm/wala/cast/python/ml/client/TensorGenerator.java | Implements interprocedural shape-vector provenance via callee-return walking and updates shape-vector structural recognition accordingly. |
| com.ibm.wala.cast.python.ml/source/com/ibm/wala/cast/python/ml/client/PythonTensorAnalysisEngine.java | Updates the shape-vector structural check call site to pass the builder after the signature change. |
| com.ibm.wala.cast.python.test/data/tf2_test_shape_helper_slice.py | Adds a fixture covering helper-return [-2:] slicing feeding tf.reshape. |
| com.ibm.wala.cast.python.test/data/tf2_test_shape_helper_slice_var.py | Adds a fixture combining helper-return provenance with [-k:] (negated variable bound) slicing. |
| com.ibm.wala.cast.python.ml.test/source/com/ibm/wala/cast/python/ml/test/TestTensorflow2Model.java | Adds tests validating precise (5, 6) inference for both new helper fixtures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #554 +/- ##
============================================
+ Coverage 74.31% 74.32% +0.01%
- Complexity 3591 3601 +10
============================================
Files 304 304
Lines 23341 23391 +50
Branches 3966 3985 +19
============================================
+ Hits 17346 17386 +40
+ Misses 4388 4385 -3
- Partials 1607 1620 +13 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Address review feedback: a helper mixing value-returns with a bare `return` can produce no value (None) on some path, so both the shape walk and the structural chain check now treat the call as unresolvable rather than skipping the bare return. Also document the chain check's `builder` parameter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019qw3CqL43aLvPaj1xkWQ2m
The previous commit claimed this fix but carried only the Javadoc change: the edit script aborted on a failed anchor before writing the code. A helper mixing value-returns with a bare `return` can produce no value (None) on some path, so the shape walk now returns ⊤ and the structural chain check returns false on a bare return instead of skipping it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019qw3CqL43aLvPaj1xkWQ2m
The uncovered lines are the interprocedural walk's sound-fallback guards: the bare-return and recursive-helper rejections, the callee-without-IR and no-return degradations, and their mirrors in the structural chain check. Forcing them requires helpers whose degenerate form ( |
Closes wala#706.
The shape-vector provenance walk (wala#703, #552) was intraprocedural, so a shape list produced by a user helper (the BERT/ALBERT
get_shape_listpattern) stopped it at the helper's invoke and reported ⊤; one context additionally leaked the input tensor's shape throughReshape's fallback because the chain check didn't recognize the helper form.What Changed
getShapesOfShapeVectorresolves a helper invoke's call-graph targets and walks every callee's returned value through the same chain recognition, unioning across callees and returns and falling back to ⊤ when any return doesn't resolve. No explicit parameter-to-argument mapping is needed: the callee parameter's interprocedural points-to set already holds the caller's allocation, so the.shapebase case resolves across the boundary. A visited set threaded through the recursion guards recursive helpers.isShapeVectorChainmirrors the interprocedural case (and now takes the builder), so the legacy pin's skip case andReshape's ⊤-guard recognize the helper form.Coverage
testShapeHelperSlicepins the precise(5, 6)forget_shape(t)[-2:].testShapeHelperSliceVarcombines the hop with the negated variable bound from #553 (get_shape(t)[-k:]), which is structurally NLPGNN'seinsum_via_matmulshape read (get_shape_list(input_tensor)[-num_inner_dims:]).🤖 Generated with Claude Code