modify-shaped-array-dsl
Úsalo cuando Pyrefly calcule una forma de tensor incorrecta (o falte una que no se pueda expresar en una firma stub) y necesites agregar o corregir una regla de shape-DSL.
npx skills add https://github.com/facebook/pyrefly --skill modify-shaped-array-dslYou are modifying Pyrefly's tensor-shape DSL — the logic that computes the output shape of a torch op from its input shapes.
This skill points at code; it does not duplicate it. Read the files below to learn the details. What follows is only the map and the invariant you must uphold (add a unit test).
How the DSL works (the 30-second version)
A shape rule is a Python function in
tensor-shapes/pyrefly-torch-stubs/torch-stubs/_shapes.pyi, decorated with
@type_shape_dsl_function, that computes a type-level value using a restricted
Python subset. Public stubs call the function directly in return annotations,
for example Tensor[reshape(Shape, Target)]. The checker validates and
evaluates these calls; CPython treats the decorator as a runtime no-op.
There are two kinds of change. A stub-only change edits _shapes.pyi and the
public return annotation to compose existing operations. A DSL-kernel change
edits the Rust validator or evaluator to add a genuinely new operation; reach
for it only when the rule cannot be expressed by composing the existing DSL.
For a stub parameter that accepts either an integer tuple or list, use
IntTupleOrList[Values] with Values: IntTuple. Direct, unstarred list literals
bind their values; existing and starred lists remain gradual, while direct
literals containing non-integers are rejected. This is a stub-signature feature,
not a reason to add list handling to a DSL kernel.
The type-level DSL implementation lives primarily in
crates/pyrefly_types/src/type_level_dsl.rs, with separate modules for type
system operations such as MapIntTuples. The symbolic dimension algebra it
uses lives in crates/pyrefly_types/src/dimension.rs.
Preserve tensor types in numeric formulas
Integer/float arithmetic overloads can sometimes cause a tensor expression to
lose type information during overload selection. In tensor code, make formulas
explicitly floating-point when the result is intended to remain a tensor. For
example, multiply an exponent by 1.0, or use a floating-point base such as
2.0 instead of 2. These equivalent forms steer overload selection toward
floating-point tensor arithmetic.
Spell gradual shapes canonically
Use int for a gradual dimension, IntTuple for a gradual whole shape, and
bare Int for a gradual shape integer. For example, prefer Tensor[[int, 3]]
to Tensor[[Any, 3]], Tensor[IntTuple] to Tensor[Any], and Int to
Int[Any]. The Any spellings remain legal for compatibility, but use them
only when a test specifically exercises Any propagation.
Test the layer you change
For a stub-only change in _shapes.pyi that composes existing DSL operations,
add a focused test to that library's static shape corpus and a runtime
cross-check where possible. Do not duplicate the stub rule in
pyrefly/lib/test/shape_dsl.rs; such a test does not exercise the implementation
that changed.
For a DSL-kernel change, add a targeted test in
pyrefly/lib/test/shape_dsl.rs. An end-to-end example alone does not pin the
kernel behavior, so explicitly cover the relevant algebra and edge cases. Read
nearby type-level DSL tests before adding one. Use assert_type when the expected
type is expressible and inline # E: ... markers for diagnostics. Tests for the
retained V1 kernel compatibility path are isolated in the legacy module and
should not be used as templates for new rules.
Run a kernel test with:
- buck:
buck test fbcode//pyrefly:test-library -- <test_name> - cargo:
cargo test <test_name>
After a DSL-kernel (Rust) change you must rebuild before the checker sees it:
buck build fbcode//pyrefly:pyrefly (or cargo build). Stub-only _shapes.pyi
edits need no rebuild.
For any DSL-kernel or broader Pyrefly core change that modifies shape manipulation semantics (as opposed to only editing torch/numpy stubs), the default verification gate is:
tensor-shapes/run_all_shape_tests.py
This gate runs the shape-relevant Rust unit tests plus the non-runtime
tensor-shape corpus tests, and defaults to cargo with automatic buck fallback.
Use --mode buck or --mode cargo when you need to pin the backend, and add
--include-runtime-tests only when runtime coverage is relevant.
Contributing the change
- fbsource: land as a diff.
- clone: open a PR against the stubs / Rust source in place.