fix Preliminary support for class decorators #2752#2773
fix Preliminary support for class decorators #2752#2773asukaminato0721 wants to merge 5 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR enhances Pyrefly’s solver to type-check class decorator application so the decorated class name can be rebound to the decorator’s return type (e.g., @remote turning a class name into an ActorHandle[...]), and adds a regression test covering this behavior.
Changes:
- Apply non-dataclass-transform class decorators during
Binding::ClassDeftype solving to infer the post-decoration value type. - Extend
untype_opt/expr_untypehandling forType::KwCalland name lookups to better support the new decorator behavior. - Add a new decorator test case ensuring a class decorator can rebind the class value.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
pyrefly/lib/test/decorators.rs |
Adds a regression testcase for a class decorator that rebinds the class symbol to an ActorHandle[T]. |
pyrefly/lib/alt/solve.rs |
Implements class-decorator application during solving and adjusts untyping/name handling to support the new behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@migeed-z why does this get classified as "improvement" lol |
This comment has been minimized.
This comment has been minimized.
Primer Diff Classification❌ 2 regression(s) | ✅ 2 improvement(s) | 4 project(s) total | +7 errors 2 regression(s) across jax, django-modern-rest. error kinds:
Detailed analysis❌ Regression (2)jax (+4)
django-modern-rest (+1)
✅ Improvement (2)spark (+1)
django-stubs (+1)
Suggested fixesSummary: The new class decorator handling in solve.rs produces false positive errors when decorators return the class unchanged but pyrefly's heuristic fails to detect this, and when call_infer triggers spurious type argument resolution for generic classes. 1. In the Binding::ClassDef match arm in solve.rs (around line 5280-5305), the heuristic for preserving the original class type after decorator application is too narrow. When
2. In the Binding::ClassDef decorator loop in solve.rs (around line 5290), the call to
Was this helpful? React with 👍 or 👎 Classification by primer-classifier (4 LLM) |
|
Diff from mypy_primer, showing the effect of this PR on open source code: jax (https://github.com/google/jax)
+ ERROR jax/experimental/array_serialization/serialization_test.py:820:1-821:38: `GenericResidual@Typ` is not assignable to upper bound `type[Any]` of type variable `Typ` [bad-specialization]
+ ERROR jax/experimental/array_serialization/serialization_test.py:950:5-951:38: `GenericResidual@Typ` is not assignable to upper bound `type[Any]` of type variable `Typ` [bad-specialization]
+ ERROR jax/experimental/array_serialization/serialization_test.py:963:5-35: `UserPytreeAPITest.test_custom_node_registration.P` is not assignable to upper bound `Hashable` of type variable `H` [bad-specialization]
+ ERROR jax/experimental/array_serialization/serialization_test.py:968:5-969:43: `GenericResidual@Typ` is not assignable to upper bound `type[Any]` of type variable `Typ` [bad-specialization]
spark (https://github.com/apache/spark)
+ ERROR python/pyspark/testing/tests/test_skip_class.py:20:1-15: Argument `type[SkipClassTests]` is not assignable to parameter `reason` with type `str` in function `unittest.case.skip` [bad-argument-type]
django-modern-rest (https://github.com/wemake-services/django-modern-rest)
+ ERROR dmr/streaming/sse/metadata.py:37:1-7: Cannot determine the type parameter `_DataT_co` for generic class `SSEvent` [implicit-any-type-argument]
|
Primer Diff Classification❌ 2 regression(s) | ✅ 1 improvement(s) | 3 project(s) total | +6 errors 2 regression(s) across jax, django-modern-rest. error kinds:
Detailed analysis❌ Regression (2)jax (+4)
The key issue is that pyrefly's new decorator processing is incorrectly resolving type variable bindings when calling these JAX utility decorators. The
django-modern-rest (+1)
✅ Improvement (1)spark (+1)
Suggested fixesSummary: The new class decorator processing in solve.rs introduces false positive errors when decorators are applied to generic classes, because the class type passed to call_infer carries unresolved type parameters that fail bound checks. 1. In the Binding::ClassDef match arm in solve.rs (around line 5290), when constructing the
2. In the Binding::ClassDef match arm in solve.rs (around line 5310-5320), the decorator result handling logic checks
Was this helpful? React with 👍 or 👎 Classification by primer-classifier (3 LLM) |
|
Diff from mypy_primer, showing the effect of this PR on open source code: spark (https://github.com/apache/spark)
+ ERROR python/pyspark/testing/tests/test_skip_class.py:20:1-15: Argument `type[SkipClassTests]` is not assignable to parameter `reason` with type `str` in function `unittest.case.skip` [bad-argument-type]
jax (https://github.com/google/jax)
+ ERROR jax/experimental/array_serialization/serialization_test.py:820:1-821:38: `GenericResidual@Typ` is not assignable to upper bound `type[Any]` of type variable `Typ` [bad-specialization]
+ ERROR jax/experimental/array_serialization/serialization_test.py:950:5-951:38: `GenericResidual@Typ` is not assignable to upper bound `type[Any]` of type variable `Typ` [bad-specialization]
+ ERROR jax/experimental/array_serialization/serialization_test.py:963:5-35: `UserPytreeAPITest.test_custom_node_registration.P` is not assignable to upper bound `Hashable` of type variable `H` [bad-specialization]
+ ERROR jax/experimental/array_serialization/serialization_test.py:968:5-969:43: `GenericResidual@Typ` is not assignable to upper bound `type[Any]` of type variable `Typ` [bad-specialization]
django-modern-rest (https://github.com/wemake-services/django-modern-rest)
+ ERROR dmr/streaming/sse/metadata.py:37:1-7: Cannot determine the type parameter `_DataT_co` for generic class `SSEvent` [implicit-any-type-argument]
|
Primer Diff Classification❌ 2 regression(s) | ✅ 1 improvement(s) | 3 project(s) total | +6 errors 2 regression(s) across jax, django-modern-rest. error kinds:
Detailed analysis❌ Regression (2)jax (+4)
The fourth error (line 963) is different in nature. It reports that
django-modern-rest (+1)
✅ Improvement (1)spark (+1)
Suggested fixesSummary: The new class decorator processing logic in solve.rs causes false positive errors when decorators like @Final don't change the class type, and when decorator return types contain unresolved generic type variables. 1. In the Binding::ClassDef match arm in solve.rs (around line 5270), add a check to skip decorators that are known to be identity-like (such as
2. In the Binding::ClassDef match arm in solve.rs (around line 5270), when
3. In the Binding::ClassDef decorator loop in solve.rs, pass errors to a separate error collector (or use a 'tentative' error mode) during
Was this helpful? React with 👍 or 👎 Classification by primer-classifier (3 LLM) |
|
Diff from mypy_primer, showing the effect of this PR on open source code: jax (https://github.com/google/jax)
+ ERROR jax/experimental/array_serialization/serialization_test.py:946:5-949:55: Argument `type[UserPytreeAPITest.test_register_as_decorator.CustomDNode]` is not assignable to parameter `nodetype` with type `type[T]` [bad-argument-type]
+ ERROR jax/experimental/array_serialization/serialization_test.py:963:5-35: `UserPytreeAPITest.test_custom_node_registration.P` is not assignable to upper bound `Hashable` of type variable `H` [bad-specialization]
spark (https://github.com/apache/spark)
+ ERROR python/pyspark/testing/tests/test_skip_class.py:20:1-15: Argument `type[SkipClassTests]` is not assignable to parameter `reason` with type `str` in function `unittest.case.skip` [bad-argument-type]
django-modern-rest (https://github.com/wemake-services/django-modern-rest)
+ ERROR dmr/streaming/sse/metadata.py:37:1-7: Cannot determine the type parameter `_DataT_co` for generic class `SSEvent[_DataT_co]` [implicit-any-type-argument]
|
General class-decorator application overlapped with main's handling of untyped decorators and explicit type[Any] erasure. Preserve those diagnostics and escape-hatch semantics while applying typed decorators that transform runtime class values.
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
Summary
Fixes #2752
applying class decorators to the runtime class-value bindingm while preserving the original class object when a decorator still returns a usable type form.
Test Plan
add test